blob: e9bd52389dc71493a1a1d3c43278db7d48893615 [file]
// Licensed to Apache Software Foundation (ASF) under one or more contributor
// license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright
// ownership. Apache Software Foundation (ASF) licenses this file to you under
// the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package cmdsetup
import (
"context"
"sync"
"time"
"github.com/apache/skywalking-banyandb/pkg/logger"
"github.com/apache/skywalking-banyandb/pkg/panicdiag"
)
// supervisor owns the process-wide panic cancel context and artifact sink.
var (
supervisorOnce sync.Once
supervisorCtx context.Context
supervisorCancel context.CancelFunc
supervisorSink *panicdiag.ArtifactSink
)
// supervisorShutdownDeadline bounds artifact sink drain during shutdown.
const supervisorShutdownDeadline = 10 * time.Second
// initSupervisor installs the process-wide panic cancel hook and sink.
func initSupervisor() {
supervisorOnce.Do(func() {
supervisorCtx, supervisorCancel = context.WithCancel(context.Background())
panicdiag.SetDefaultAbortFunc(func(_ context.Context, result panicdiag.RecoveryResult) {
component := ""
panicValue := ""
if result.Record != nil {
component = result.Record.Component
panicValue = result.Record.PanicValue
}
logger.GetLogger("supervisor").Error().
Str("component", component).
Str("panic", panicValue).
Msg("canceling supervising context due to recovered panic")
supervisorCancel()
})
supervisorSink = panicdiag.NewArtifactSink(0)
supervisorSink.Start()
panicdiag.SetDefaultArtifactSink(supervisorSink)
})
}
// SupervisorContext returns the process-wide supervising context. It is
// canceled when any panicdiag-protected goroutine recovers a panic, allowing
// long-running work elsewhere in the process to wind down gracefully.
// The context is initialized by NewRoot's PersistentPreRunE; callers that
// fetch it before initialization receive a never-canceled context.Background.
func SupervisorContext() context.Context {
if supervisorCtx == nil {
return context.Background()
}
return supervisorCtx
}
// ShutdownSupervisor drains and unregisters the process-wide artifact sink.
func ShutdownSupervisor() {
if supervisorSink == nil {
return
}
ctx, cancel := context.WithTimeout(context.Background(), supervisorShutdownDeadline)
defer cancel()
if err := supervisorSink.Close(ctx); err != nil {
logger.GetLogger("supervisor").Warn().
Err(err).
Dur("deadline", supervisorShutdownDeadline).
Msg("artifact sink did not drain before shutdown deadline; pending artifacts dropped")
}
panicdiag.SetDefaultArtifactSink(nil)
}