fix all panichandlers for the new format (inline recover()) (#1659)

This commit is contained in:
Mike Sawka 2024-12-31 09:31:55 -08:00 committed by GitHub
parent 7d0fb0391f
commit fe91d167b6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
32 changed files with 207 additions and 87 deletions

View File

@ -120,7 +120,9 @@ func panicTelemetryHandler() {
} }
func sendTelemetryWrapper() { func sendTelemetryWrapper() {
defer panichandler.PanicHandler("sendTelemetryWrapper") defer func() {
panichandler.PanicHandler("sendTelemetryWrapper", recover())
}()
ctx, cancelFn := context.WithTimeout(context.Background(), 5*time.Second) ctx, cancelFn := context.WithTimeout(context.Background(), 5*time.Second)
defer cancelFn() defer cancelFn()
beforeSendActivityUpdate(ctx) beforeSendActivityUpdate(ctx)
@ -270,7 +272,9 @@ func main() {
} }
panichandler.PanicTelemetryHandler = panicTelemetryHandler panichandler.PanicTelemetryHandler = panicTelemetryHandler
go func() { go func() {
defer panichandler.PanicHandler("InitCustomShellStartupFiles") defer func() {
panichandler.PanicHandler("InitCustomShellStartupFiles", recover())
}()
err := shellutil.InitCustomShellStartupFiles() err := shellutil.InitCustomShellStartupFiles()
if err != nil { if err != nil {
log.Printf("error initializing wsh and shell-integration files: %v\n", err) log.Printf("error initializing wsh and shell-integration files: %v\n", err)

View File

@ -60,7 +60,9 @@ func handleNewListenerConn(conn net.Conn, router *wshutil.WshRouter) {
var routeIdContainer atomic.Pointer[string] var routeIdContainer atomic.Pointer[string]
proxy := wshutil.MakeRpcProxy() proxy := wshutil.MakeRpcProxy()
go func() { go func() {
defer panichandler.PanicHandler("handleNewListenerConn:AdaptOutputChToStream") defer func() {
panichandler.PanicHandler("handleNewListenerConn:AdaptOutputChToStream", recover())
}()
writeErr := wshutil.AdaptOutputChToStream(proxy.ToRemoteCh, conn) writeErr := wshutil.AdaptOutputChToStream(proxy.ToRemoteCh, conn)
if writeErr != nil { if writeErr != nil {
log.Printf("error writing to domain socket: %v\n", writeErr) log.Printf("error writing to domain socket: %v\n", writeErr)
@ -68,7 +70,9 @@ func handleNewListenerConn(conn net.Conn, router *wshutil.WshRouter) {
}() }()
go func() { go func() {
// when input is closed, close the connection // when input is closed, close the connection
defer panichandler.PanicHandler("handleNewListenerConn:AdaptStreamToMsgCh") defer func() {
panichandler.PanicHandler("handleNewListenerConn:AdaptStreamToMsgCh", recover())
}()
defer func() { defer func() {
conn.Close() conn.Close()
routeIdPtr := routeIdContainer.Load() routeIdPtr := routeIdContainer.Load()
@ -145,7 +149,9 @@ func serverRunRouter() error {
rawCh := make(chan []byte, wshutil.DefaultOutputChSize) rawCh := make(chan []byte, wshutil.DefaultOutputChSize)
go packetparser.Parse(os.Stdin, termProxy.FromRemoteCh, rawCh) go packetparser.Parse(os.Stdin, termProxy.FromRemoteCh, rawCh)
go func() { go func() {
defer panichandler.PanicHandler("serverRunRouter:WritePackets") defer func() {
panichandler.PanicHandler("serverRunRouter:WritePackets", recover())
}()
for msg := range termProxy.ToRemoteCh { for msg := range termProxy.ToRemoteCh {
packetparser.WritePacket(os.Stdout, msg) packetparser.WritePacket(os.Stdout, msg)
} }

View File

@ -426,7 +426,9 @@ func (bc *BlockController) DoRunShellCommand(rc *RunShellOpts, blockMeta waveobj
ptyBuffer := wshutil.MakePtyBuffer(wshutil.WaveOSCPrefix, shellProc.Cmd, wshProxy.FromRemoteCh) ptyBuffer := wshutil.MakePtyBuffer(wshutil.WaveOSCPrefix, shellProc.Cmd, wshProxy.FromRemoteCh)
go func() { go func() {
// handles regular output from the pty (goes to the blockfile and xterm) // handles regular output from the pty (goes to the blockfile and xterm)
defer panichandler.PanicHandler("blockcontroller:shellproc-pty-read-loop") defer func() {
panichandler.PanicHandler("blockcontroller:shellproc-pty-read-loop", recover())
}()
defer func() { defer func() {
log.Printf("[shellproc] pty-read loop done\n") log.Printf("[shellproc] pty-read loop done\n")
shellProc.Close() shellProc.Close()
@ -463,7 +465,9 @@ func (bc *BlockController) DoRunShellCommand(rc *RunShellOpts, blockMeta waveobj
go func() { go func() {
// handles input from the shellInputCh, sent to pty // handles input from the shellInputCh, sent to pty
// use shellInputCh instead of bc.ShellInputCh (because we want to be attached to *this* ch. bc.ShellInputCh can be updated) // use shellInputCh instead of bc.ShellInputCh (because we want to be attached to *this* ch. bc.ShellInputCh can be updated)
defer panichandler.PanicHandler("blockcontroller:shellproc-input-loop") defer func() {
panichandler.PanicHandler("blockcontroller:shellproc-input-loop", recover())
}()
for ic := range shellInputCh { for ic := range shellInputCh {
if len(ic.InputData) > 0 { if len(ic.InputData) > 0 {
shellProc.Cmd.Write(ic.InputData) shellProc.Cmd.Write(ic.InputData)
@ -481,7 +485,9 @@ func (bc *BlockController) DoRunShellCommand(rc *RunShellOpts, blockMeta waveobj
} }
}() }()
go func() { go func() {
defer panichandler.PanicHandler("blockcontroller:shellproc-output-loop") defer func() {
panichandler.PanicHandler("blockcontroller:shellproc-output-loop", recover())
}()
// handles outputCh -> shellInputCh // handles outputCh -> shellInputCh
for msg := range wshProxy.ToRemoteCh { for msg := range wshProxy.ToRemoteCh {
encodedMsg, err := wshutil.EncodeWaveOSCBytes(wshutil.WaveServerOSC, msg) encodedMsg, err := wshutil.EncodeWaveOSCBytes(wshutil.WaveServerOSC, msg)
@ -492,7 +498,9 @@ func (bc *BlockController) DoRunShellCommand(rc *RunShellOpts, blockMeta waveobj
} }
}() }()
go func() { go func() {
defer panichandler.PanicHandler("blockcontroller:shellproc-wait-loop") defer func() {
panichandler.PanicHandler("blockcontroller:shellproc-wait-loop", recover())
}()
// wait for the shell to finish // wait for the shell to finish
var exitCode int var exitCode int
defer func() { defer func() {
@ -631,7 +639,9 @@ func (bc *BlockController) run(bdata *waveobj.Block, blockMeta map[string]any, r
} }
runningShellCommand = true runningShellCommand = true
go func() { go func() {
defer panichandler.PanicHandler("blockcontroller:run-shell-command") defer func() {
panichandler.PanicHandler("blockcontroller:run-shell-command", recover())
}()
defer bc.UnlockRunLock() defer bc.UnlockRunLock()
var termSize waveobj.TermSize var termSize waveobj.TermSize
if rtOpts != nil { if rtOpts != nil {

View File

@ -514,7 +514,9 @@ func (s *FileStore) runFlushWithNewContext() (FlushStats, error) {
} }
func (s *FileStore) runFlusher() { func (s *FileStore) runFlusher() {
defer panichandler.PanicHandler("filestore flusher") defer func() {
panichandler.PanicHandler("filestore flusher", recover())
}()
for { for {
stats, err := s.runFlushWithNewContext() stats, err := s.runFlushWithNewContext()
if err != nil || stats.NumDirtyEntries > 0 { if err != nil || stats.NumDirtyEntries > 0 {

View File

@ -13,31 +13,29 @@ import (
// gets around import cycles // gets around import cycles
var PanicTelemetryHandler func() var PanicTelemetryHandler func()
func PanicHandlerNoTelemetry(debugStr string) { func PanicHandlerNoTelemetry(debugStr string, recoverVal any) {
r := recover() if recoverVal == nil {
if r == nil {
return return
} }
log.Printf("[panic] in %s: %v\n", debugStr, r) log.Printf("[panic] in %s: %v\n", debugStr, recoverVal)
debug.PrintStack() debug.PrintStack()
} }
// returns an error (wrapping the panic) if a panic occurred // returns an error (wrapping the panic) if a panic occurred
func PanicHandler(debugStr string) error { func PanicHandler(debugStr string, recoverVal any) error {
r := recover() if recoverVal == nil {
if r == nil {
return nil return nil
} }
log.Printf("[panic] in %s: %v\n", debugStr, r) log.Printf("[panic] in %s: %v\n", debugStr, recoverVal)
debug.PrintStack() debug.PrintStack()
if PanicTelemetryHandler != nil { if PanicTelemetryHandler != nil {
go func() { go func() {
defer PanicHandlerNoTelemetry("PanicTelemetryHandler") defer PanicHandlerNoTelemetry("PanicTelemetryHandler", recover())
PanicTelemetryHandler() PanicTelemetryHandler()
}() }()
} }
if err, ok := r.(error); ok { if err, ok := recoverVal.(error); ok {
return fmt.Errorf("panic in %s: %w", debugStr, err) return fmt.Errorf("panic in %s: %w", debugStr, err)
} }
return fmt.Errorf("panic in %s: %v", debugStr, r) return fmt.Errorf("panic in %s: %v", debugStr, recoverVal)
} }

View File

@ -198,7 +198,9 @@ func (conn *SSHConn) OpenDomainSocketListener() error {
conn.DomainSockListener = listener conn.DomainSockListener = listener
}) })
go func() { go func() {
defer panichandler.PanicHandler("conncontroller:OpenDomainSocketListener") defer func() {
panichandler.PanicHandler("conncontroller:OpenDomainSocketListener", recover())
}()
defer conn.WithLock(func() { defer conn.WithLock(func() {
conn.DomainSockListener = nil conn.DomainSockListener = nil
conn.SockName = "" conn.SockName = ""
@ -258,7 +260,9 @@ func (conn *SSHConn) StartConnServer() error {
}) })
// service the I/O // service the I/O
go func() { go func() {
defer panichandler.PanicHandler("conncontroller:sshSession.Wait") defer func() {
panichandler.PanicHandler("conncontroller:sshSession.Wait", recover())
}()
// wait for termination, clear the controller // wait for termination, clear the controller
defer conn.WithLock(func() { defer conn.WithLock(func() {
conn.ConnController = nil conn.ConnController = nil
@ -267,7 +271,9 @@ func (conn *SSHConn) StartConnServer() error {
log.Printf("conn controller (%q) terminated: %v", conn.GetName(), waitErr) log.Printf("conn controller (%q) terminated: %v", conn.GetName(), waitErr)
}() }()
go func() { go func() {
defer panichandler.PanicHandler("conncontroller:sshSession-output") defer func() {
panichandler.PanicHandler("conncontroller:sshSession-output", recover())
}()
readErr := wshutil.StreamToLines(pipeRead, func(line []byte) { readErr := wshutil.StreamToLines(pipeRead, func(line []byte) {
lineStr := string(line) lineStr := string(line)
if !strings.HasSuffix(lineStr, "\n") { if !strings.HasSuffix(lineStr, "\n") {

View File

@ -274,7 +274,9 @@ func CpHostToRemote(client *ssh.Client, sourcePath string, destPath string) erro
} }
go func() { go func() {
defer panichandler.PanicHandler("connutil:CpHostToRemote") defer func() {
panichandler.PanicHandler("connutil:CpHostToRemote", recover())
}()
io.Copy(installStdin, input) io.Copy(installStdin, input)
session.Close() // this allows the command to complete for reasons i don't fully understand session.Close() // this allows the command to complete for reasons i don't fully understand
}() }()

View File

@ -720,9 +720,9 @@ func ConnectToClient(connCtx context.Context, opts *SSHOpts, currentClient *ssh.
// when given unexpected strings // when given unexpected strings
func findSshConfigKeywords(hostPattern string) (connKeywords *wshrpc.ConnKeywords, outErr error) { func findSshConfigKeywords(hostPattern string) (connKeywords *wshrpc.ConnKeywords, outErr error) {
defer func() { defer func() {
err := panichandler.PanicHandler("sshclient:find-ssh-config-keywords") panicErr := panichandler.PanicHandler("sshclient:find-ssh-config-keywords", recover())
if err != nil { if panicErr != nil {
outErr = err outErr = panicErr
} }
}() }()
WaveSshConfigUserSettings().ReloadConfigs() WaveSshConfigUserSettings().ReloadConfigs()

View File

@ -151,7 +151,9 @@ func (svc *WindowService) SwitchWorkspace(ctx context.Context, windowId string,
updates := waveobj.ContextGetUpdatesRtn(ctx) updates := waveobj.ContextGetUpdatesRtn(ctx)
go func() { go func() {
defer panichandler.PanicHandler("WindowService:SwitchWorkspace:SendUpdateEvents") defer func() {
panichandler.PanicHandler("WindowService:SwitchWorkspace:SendUpdateEvents", recover())
}()
wps.Broker.SendUpdateEvents(updates) wps.Broker.SendUpdateEvents(updates)
}() }()
return ws, err return ws, err

View File

@ -59,7 +59,9 @@ func (svc *WorkspaceService) UpdateWorkspace(ctx context.Context, workspaceId st
updates := waveobj.ContextGetUpdatesRtn(ctx) updates := waveobj.ContextGetUpdatesRtn(ctx)
go func() { go func() {
defer panichandler.PanicHandler("WorkspaceService:UpdateWorkspace:SendUpdateEvents") defer func() {
panichandler.PanicHandler("WorkspaceService:UpdateWorkspace:SendUpdateEvents", recover())
}()
wps.Broker.SendUpdateEvents(updates) wps.Broker.SendUpdateEvents(updates)
}() }()
return updates, nil return updates, nil
@ -104,7 +106,9 @@ func (svc *WorkspaceService) DeleteWorkspace(workspaceId string) (waveobj.Update
} }
updates := waveobj.ContextGetUpdatesRtn(ctx) updates := waveobj.ContextGetUpdatesRtn(ctx)
go func() { go func() {
defer panichandler.PanicHandler("WorkspaceService:DeleteWorkspace:SendUpdateEvents") defer func() {
panichandler.PanicHandler("WorkspaceService:DeleteWorkspace:SendUpdateEvents", recover())
}()
wps.Broker.SendUpdateEvents(updates) wps.Broker.SendUpdateEvents(updates)
}() }()
return updates, claimableWorkspace, nil return updates, claimableWorkspace, nil
@ -153,7 +157,9 @@ func (svc *WorkspaceService) CreateTab(workspaceId string, tabName string, activ
} }
updates := waveobj.ContextGetUpdatesRtn(ctx) updates := waveobj.ContextGetUpdatesRtn(ctx)
go func() { go func() {
defer panichandler.PanicHandler("WorkspaceService:CreateTab:SendUpdateEvents") defer func() {
panichandler.PanicHandler("WorkspaceService:CreateTab:SendUpdateEvents", recover())
}()
wps.Broker.SendUpdateEvents(updates) wps.Broker.SendUpdateEvents(updates)
}() }()
return tabId, updates, nil return tabId, updates, nil
@ -174,7 +180,9 @@ func (svc *WorkspaceService) ChangeTabPinning(ctx context.Context, workspaceId s
} }
updates := waveobj.ContextGetUpdatesRtn(ctx) updates := waveobj.ContextGetUpdatesRtn(ctx)
go func() { go func() {
defer panichandler.PanicHandler("WorkspaceService:ChangeTabPinning:SendUpdateEvents") defer func() {
panichandler.PanicHandler("WorkspaceService:ChangeTabPinning:SendUpdateEvents", recover())
}()
wps.Broker.SendUpdateEvents(updates) wps.Broker.SendUpdateEvents(updates)
}() }()
return updates, nil return updates, nil
@ -224,7 +232,9 @@ func (svc *WorkspaceService) SetActiveTab(workspaceId string, tabId string) (wav
} }
updates := waveobj.ContextGetUpdatesRtn(ctx) updates := waveobj.ContextGetUpdatesRtn(ctx)
go func() { go func() {
defer panichandler.PanicHandler("WorkspaceService:SetActiveTab:SendUpdateEvents") defer func() {
panichandler.PanicHandler("WorkspaceService:SetActiveTab:SendUpdateEvents", recover())
}()
wps.Broker.SendUpdateEvents(updates) wps.Broker.SendUpdateEvents(updates)
}() }()
var extraUpdates waveobj.UpdatesRtnType var extraUpdates waveobj.UpdatesRtnType
@ -270,7 +280,9 @@ func (svc *WorkspaceService) CloseTab(ctx context.Context, workspaceId string, t
} }
updates := waveobj.ContextGetUpdatesRtn(ctx) updates := waveobj.ContextGetUpdatesRtn(ctx)
go func() { go func() {
defer panichandler.PanicHandler("WorkspaceService:CloseTab:SendUpdateEvents") defer func() {
panichandler.PanicHandler("WorkspaceService:CloseTab:SendUpdateEvents", recover())
}()
wps.Broker.SendUpdateEvents(updates) wps.Broker.SendUpdateEvents(updates)
}() }()
return rtn, updates, nil return rtn, updates, nil

View File

@ -76,7 +76,9 @@ func (cw CmdWrap) KillGraceful(timeout time.Duration) {
cw.Cmd.Process.Signal(syscall.SIGTERM) cw.Cmd.Process.Signal(syscall.SIGTERM)
} }
go func() { go func() {
defer panichandler.PanicHandler("KillGraceful:Kill") defer func() {
panichandler.PanicHandler("KillGraceful:Kill", recover())
}()
time.Sleep(timeout) time.Sleep(timeout)
if cw.Cmd.ProcessState == nil || !cw.Cmd.ProcessState.Exited() { if cw.Cmd.ProcessState == nil || !cw.Cmd.ProcessState.Exited() {
cw.Cmd.Process.Kill() // force kill if it is already not exited cw.Cmd.Process.Kill() // force kill if it is already not exited
@ -208,7 +210,9 @@ func (wcw WslCmdWrap) KillGraceful(timeout time.Duration) {
} }
process.Signal(os.Interrupt) process.Signal(os.Interrupt)
go func() { go func() {
defer panichandler.PanicHandler("KillGraceful-wsl:Kill") defer func() {
panichandler.PanicHandler("KillGraceful-wsl:Kill", recover())
}()
time.Sleep(timeout) time.Sleep(timeout)
process := wcw.WslCmd.GetProcess() process := wcw.WslCmd.GetProcess()
processState := wcw.WslCmd.GetProcessState() processState := wcw.WslCmd.GetProcessState()

View File

@ -52,7 +52,9 @@ type ShellProc struct {
func (sp *ShellProc) Close() { func (sp *ShellProc) Close() {
sp.Cmd.KillGraceful(DefaultGracefulKillWait) sp.Cmd.KillGraceful(DefaultGracefulKillWait)
go func() { go func() {
defer panichandler.PanicHandler("ShellProc.Close") defer func() {
panichandler.PanicHandler("ShellProc.Close", recover())
}()
waitErr := sp.Cmd.Wait() waitErr := sp.Cmd.Wait()
sp.SetWaitErrorAndSignalDone(waitErr) sp.SetWaitErrorAndSignalDone(waitErr)
@ -496,7 +498,7 @@ func RunSimpleCmdInPty(ecmd *exec.Cmd, termSize waveobj.TermSize) ([]byte, error
ioDone := make(chan bool) ioDone := make(chan bool)
var outputBuf bytes.Buffer var outputBuf bytes.Buffer
go func() { go func() {
panichandler.PanicHandler("RunSimpleCmdInPty:ioCopy") panichandler.PanicHandler("RunSimpleCmdInPty:ioCopy", recover())
// ignore error (/dev/ptmx has read error when process is done) // ignore error (/dev/ptmx has read error when process is done)
defer close(ioDone) defer close(ioDone)
io.Copy(&outputBuf, cmdPty) io.Copy(&outputBuf, cmdPty)

View File

@ -83,7 +83,7 @@ func AutoUpdateChannel() string {
// Wraps UpdateCurrentActivity, spawns goroutine, and logs errors // Wraps UpdateCurrentActivity, spawns goroutine, and logs errors
func GoUpdateActivityWrap(update wshrpc.ActivityUpdate, debugStr string) { func GoUpdateActivityWrap(update wshrpc.ActivityUpdate, debugStr string) {
go func() { go func() {
defer panichandler.PanicHandlerNoTelemetry("GoUpdateActivityWrap") defer panichandler.PanicHandlerNoTelemetry("GoUpdateActivityWrap", recover())
ctx, cancelFn := context.WithTimeout(context.Background(), 5*time.Second) ctx, cancelFn := context.WithTimeout(context.Background(), 5*time.Second)
defer cancelFn() defer cancelFn()
err := UpdateActivity(ctx, update) err := UpdateActivity(ctx, update)

View File

@ -114,7 +114,7 @@ func (AnthropicBackend) StreamCompletion(ctx context.Context, request wshrpc.Wav
go func() { go func() {
defer func() { defer func() {
panicErr := panichandler.PanicHandler("AnthropicBackend.StreamCompletion") panicErr := panichandler.PanicHandler("AnthropicBackend.StreamCompletion", recover())
if panicErr != nil { if panicErr != nil {
rtn <- makeAIError(panicErr) rtn <- makeAIError(panicErr)
} }

View File

@ -44,7 +44,7 @@ func (WaveAICloudBackend) StreamCompletion(ctx context.Context, request wshrpc.W
wsEndpoint := wcloud.GetWSEndpoint() wsEndpoint := wcloud.GetWSEndpoint()
go func() { go func() {
defer func() { defer func() {
panicErr := panichandler.PanicHandler("WaveAICloudBackend.StreamCompletion") panicErr := panichandler.PanicHandler("WaveAICloudBackend.StreamCompletion", recover())
if panicErr != nil { if panicErr != nil {
rtn <- makeAIError(panicErr) rtn <- makeAIError(panicErr)
} }

View File

@ -65,7 +65,7 @@ func (OpenAIBackend) StreamCompletion(ctx context.Context, request wshrpc.WaveAI
rtn := make(chan wshrpc.RespOrErrorUnion[wshrpc.WaveAIPacketType]) rtn := make(chan wshrpc.RespOrErrorUnion[wshrpc.WaveAIPacketType])
go func() { go func() {
defer func() { defer func() {
panicErr := panichandler.PanicHandler("OpenAIBackend.StreamCompletion") panicErr := panichandler.PanicHandler("OpenAIBackend.StreamCompletion", recover())
if panicErr != nil { if panicErr != nil {
rtn <- makeAIError(panicErr) rtn <- makeAIError(panicErr)
} }

View File

@ -54,7 +54,7 @@ func (PerplexityBackend) StreamCompletion(ctx context.Context, request wshrpc.Wa
go func() { go func() {
defer func() { defer func() {
panicErr := panichandler.PanicHandler("PerplexityBackend.StreamCompletion") panicErr := panichandler.PanicHandler("PerplexityBackend.StreamCompletion", recover())
if panicErr != nil { if panicErr != nil {
rtn <- makeAIError(panicErr) rtn <- makeAIError(panicErr)
} }

View File

@ -25,7 +25,7 @@ func (*WaveAppServerImpl) WshServerImpl() {}
func (impl *WaveAppServerImpl) VDomRenderCommand(ctx context.Context, feUpdate vdom.VDomFrontendUpdate) chan wshrpc.RespOrErrorUnion[*vdom.VDomBackendUpdate] { func (impl *WaveAppServerImpl) VDomRenderCommand(ctx context.Context, feUpdate vdom.VDomFrontendUpdate) chan wshrpc.RespOrErrorUnion[*vdom.VDomBackendUpdate] {
respChan := make(chan wshrpc.RespOrErrorUnion[*vdom.VDomBackendUpdate], 5) respChan := make(chan wshrpc.RespOrErrorUnion[*vdom.VDomBackendUpdate], 5)
defer func() { defer func() {
panicErr := panichandler.PanicHandler("VDomRenderCommand") panicErr := panichandler.PanicHandler("VDomRenderCommand", recover())
if panicErr != nil { if panicErr != nil {
respChan <- wshrpc.RespOrErrorUnion[*vdom.VDomBackendUpdate]{ respChan <- wshrpc.RespOrErrorUnion[*vdom.VDomBackendUpdate]{
Error: panicErr, Error: panicErr,
@ -88,7 +88,9 @@ func (impl *WaveAppServerImpl) VDomRenderCommand(ctx context.Context, feUpdate v
// Split the update into chunks and send them sequentially // Split the update into chunks and send them sequentially
updates := vdom.SplitBackendUpdate(update) updates := vdom.SplitBackendUpdate(update)
go func() { go func() {
defer panichandler.PanicHandler("VDomRenderCommand:splitUpdates") defer func() {
panichandler.PanicHandler("VDomRenderCommand:splitUpdates", recover())
}()
defer close(respChan) defer close(respChan)
for _, splitUpdate := range updates { for _, splitUpdate := range updates {
respChan <- wshrpc.RespOrErrorUnion[*vdom.VDomBackendUpdate]{ respChan <- wshrpc.RespOrErrorUnion[*vdom.VDomBackendUpdate]{
@ -109,7 +111,7 @@ func (impl *WaveAppServerImpl) VDomUrlRequestCommand(ctx context.Context, data w
defer writer.Close() // Ensures writer is closed before the channel is closed defer writer.Close() // Ensures writer is closed before the channel is closed
defer func() { defer func() {
panicErr := panichandler.PanicHandler("VDomUrlRequestCommand") panicErr := panichandler.PanicHandler("VDomUrlRequestCommand", recover())
if panicErr != nil { if panicErr != nil {
writer.WriteHeader(http.StatusInternalServerError) writer.WriteHeader(http.StatusInternalServerError)
writer.Write([]byte(fmt.Sprintf("internal server error: %v", panicErr))) writer.Write([]byte(fmt.Sprintf("internal server error: %v", panicErr)))

View File

@ -65,7 +65,9 @@ func (w *Watcher) Start() {
w.sendInitialValues() w.sendInitialValues()
go func() { go func() {
defer panichandler.PanicHandler("filewatcher:Start") defer func() {
panichandler.PanicHandler("filewatcher:Start", recover())
}()
for { for {
select { select {
case event, ok := <-w.watcher.Events: case event, ok := <-w.watcher.Events:

View File

@ -94,7 +94,9 @@ func CreateBlock(ctx context.Context, tabId string, blockDef *waveobj.BlockDef,
} }
} }
go func() { go func() {
defer panichandler.PanicHandler("CreateBlock:telemetry") defer func() {
panichandler.PanicHandler("CreateBlock:telemetry", recover())
}()
blockView := blockDef.Meta.GetString(waveobj.MetaKey_View, "") blockView := blockDef.Meta.GetString(waveobj.MetaKey_View, "")
if blockView == "" { if blockView == "" {
return return

View File

@ -358,7 +358,7 @@ type ClientActiveState struct {
func WebFnWrap(opts WebFnOpts, fn WebFnType) WebFnType { func WebFnWrap(opts WebFnOpts, fn WebFnType) WebFnType {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
defer func() { defer func() {
recErr := panichandler.PanicHandler("WebFnWrap") recErr := panichandler.PanicHandler("WebFnWrap", recover())
if recErr == nil { if recErr == nil {
return return
} }

View File

@ -81,7 +81,7 @@ func getStringFromMap(jmsg map[string]any, key string) string {
func processWSCommand(jmsg map[string]any, outputCh chan any, rpcInputCh chan []byte) { func processWSCommand(jmsg map[string]any, outputCh chan any, rpcInputCh chan []byte) {
var rtnErr error var rtnErr error
defer func() { defer func() {
panicErr := panichandler.PanicHandler("processWSCommand") panicErr := panichandler.PanicHandler("processWSCommand", recover())
if panicErr != nil { if panicErr != nil {
rtnErr = panicErr rtnErr = panicErr
} }
@ -302,7 +302,9 @@ func HandleWsInternal(w http.ResponseWriter, r *http.Request) error {
wg := &sync.WaitGroup{} wg := &sync.WaitGroup{}
wg.Add(2) wg.Add(2)
go func() { go func() {
defer panichandler.PanicHandler("HandleWsInternal:outputCh") defer func() {
panichandler.PanicHandler("HandleWsInternal:outputCh", recover())
}()
// no waitgroup add here // no waitgroup add here
// move values from rpcOutputCh to outputCh // move values from rpcOutputCh to outputCh
for msgBytes := range wproxy.ToRemoteCh { for msgBytes := range wproxy.ToRemoteCh {
@ -314,13 +316,17 @@ func HandleWsInternal(w http.ResponseWriter, r *http.Request) error {
} }
}() }()
go func() { go func() {
defer panichandler.PanicHandler("HandleWsInternal:ReadLoop") defer func() {
panichandler.PanicHandler("HandleWsInternal:ReadLoop", recover())
}()
// read loop // read loop
defer wg.Done() defer wg.Done()
ReadLoop(conn, outputCh, closeCh, wproxy.FromRemoteCh, routeId) ReadLoop(conn, outputCh, closeCh, wproxy.FromRemoteCh, routeId)
}() }()
go func() { go func() {
defer panichandler.PanicHandler("HandleWsInternal:WriteLoop") defer func() {
panichandler.PanicHandler("HandleWsInternal:WriteLoop", recover())
}()
// write loop // write loop
defer wg.Done() defer wg.Done()
WriteLoop(conn, outputCh, closeCh, routeId) WriteLoop(conn, outputCh, closeCh, routeId)

View File

@ -40,7 +40,9 @@ func sendRpcRequestCallHelper[T any](w *wshutil.WshRpc, command string, data int
func rtnErr[T any](ch chan wshrpc.RespOrErrorUnion[T], err error) { func rtnErr[T any](ch chan wshrpc.RespOrErrorUnion[T], err error) {
go func() { go func() {
defer panichandler.PanicHandler("wshclientutil:rtnErr") defer func() {
panichandler.PanicHandler("wshclientutil:rtnErr", recover())
}()
ch <- wshrpc.RespOrErrorUnion[T]{Error: err} ch <- wshrpc.RespOrErrorUnion[T]{Error: err}
close(ch) close(ch)
}() }()
@ -65,7 +67,9 @@ func sendRpcRequestResponseStreamHelper[T any](w *wshutil.WshRpc, command string
reqHandler.SendCancel() reqHandler.SendCancel()
} }
go func() { go func() {
defer panichandler.PanicHandler("sendRpcRequestResponseStreamHelper") defer func() {
panichandler.PanicHandler("sendRpcRequestResponseStreamHelper", recover())
}()
defer close(respChan) defer close(respChan)
for { for {
if reqHandler.ResponseDone() { if reqHandler.ResponseDone() {

View File

@ -47,7 +47,9 @@ func (*WshServer) WshServerImpl() {}
var WshServerImpl = WshServer{} var WshServerImpl = WshServer{}
func (ws *WshServer) TestCommand(ctx context.Context, data string) error { func (ws *WshServer) TestCommand(ctx context.Context, data string) error {
defer panichandler.PanicHandler("TestCommand") defer func() {
panichandler.PanicHandler("TestCommand", recover())
}()
rpcSource := wshutil.GetRpcSourceFromContext(ctx) rpcSource := wshutil.GetRpcSourceFromContext(ctx)
log.Printf("TEST src:%s | %s\n", rpcSource, data) log.Printf("TEST src:%s | %s\n", rpcSource, data)
return nil return nil
@ -63,7 +65,9 @@ func (ws *WshServer) MessageCommand(ctx context.Context, data wshrpc.CommandMess
func (ws *WshServer) StreamTestCommand(ctx context.Context) chan wshrpc.RespOrErrorUnion[int] { func (ws *WshServer) StreamTestCommand(ctx context.Context) chan wshrpc.RespOrErrorUnion[int] {
rtn := make(chan wshrpc.RespOrErrorUnion[int]) rtn := make(chan wshrpc.RespOrErrorUnion[int])
go func() { go func() {
defer panichandler.PanicHandler("StreamTestCommand") defer func() {
panichandler.PanicHandler("StreamTestCommand", recover())
}()
for i := 1; i <= 5; i++ { for i := 1; i <= 5; i++ {
rtn <- wshrpc.RespOrErrorUnion[int]{Response: i} rtn <- wshrpc.RespOrErrorUnion[int]{Response: i}
time.Sleep(1 * time.Second) time.Sleep(1 * time.Second)

View File

@ -132,7 +132,9 @@ func serverImplAdapter(impl any) func(*RpcResponseHandler) bool {
return true return true
} }
go func() { go func() {
defer panichandler.PanicHandler("serverImplAdapter:responseStream") defer func() {
panichandler.PanicHandler("serverImplAdapter:responseStream", recover())
}()
defer handler.Finalize() defer handler.Finalize()
// must use reflection here because we don't know the generic type of RespOrErrorUnion // must use reflection here because we don't know the generic type of RespOrErrorUnion
for { for {

View File

@ -113,7 +113,9 @@ func (p *WshRpcMultiProxy) handleUnauthMessage(msgBytes []byte) {
p.setRouteInfo(routeInfo.AuthToken, routeInfo) p.setRouteInfo(routeInfo.AuthToken, routeInfo)
p.sendAuthResponse(msg, routeId, routeInfo.AuthToken) p.sendAuthResponse(msg, routeId, routeInfo.AuthToken)
go func() { go func() {
defer panichandler.PanicHandler("WshRpcMultiProxy:handleUnauthMessage") defer func() {
panichandler.PanicHandler("WshRpcMultiProxy:handleUnauthMessage", recover())
}()
for msgBytes := range routeInfo.Proxy.ToRemoteCh { for msgBytes := range routeInfo.Proxy.ToRemoteCh {
p.ToRemoteCh <- msgBytes p.ToRemoteCh <- msgBytes
} }

View File

@ -92,7 +92,9 @@ func noRouteErr(routeId string) error {
} }
func (router *WshRouter) SendEvent(routeId string, event wps.WaveEvent) { func (router *WshRouter) SendEvent(routeId string, event wps.WaveEvent) {
defer panichandler.PanicHandler("WshRouter.SendEvent") defer func() {
panichandler.PanicHandler("WshRouter.SendEvent", recover())
}()
rpc := router.GetRpc(routeId) rpc := router.GetRpc(routeId)
if rpc == nil { if rpc == nil {
return return
@ -298,7 +300,9 @@ func (router *WshRouter) RegisterRoute(routeId string, rpc AbstractRpcClient, sh
} }
router.RouteMap[routeId] = rpc router.RouteMap[routeId] = rpc
go func() { go func() {
defer panichandler.PanicHandler("WshRouter:registerRoute:recvloop") defer func() {
panichandler.PanicHandler("WshRouter:registerRoute:recvloop", recover())
}()
// announce // announce
if shouldAnnounce && !alreadyExists && router.GetUpstreamClient() != nil { if shouldAnnounce && !alreadyExists && router.GetUpstreamClient() != nil {
announceMsg := RpcMessage{Command: wshrpc.Command_RouteAnnounce, Source: routeId} announceMsg := RpcMessage{Command: wshrpc.Command_RouteAnnounce, Source: routeId}
@ -344,7 +348,9 @@ func (router *WshRouter) UnregisterRoute(routeId string) {
} }
} }
go func() { go func() {
defer panichandler.PanicHandler("WshRouter:unregisterRoute:routegone") defer func() {
panichandler.PanicHandler("WshRouter:unregisterRoute:routegone", recover())
}()
wps.Broker.UnsubscribeAll(routeId) wps.Broker.UnsubscribeAll(routeId)
wps.Broker.Publish(wps.WaveEvent{Event: wps.Event_RouteGone, Scopes: []string{routeId}}) wps.Broker.Publish(wps.WaveEvent{Event: wps.Event_RouteGone, Scopes: []string{routeId}})
}() }()

View File

@ -304,13 +304,15 @@ func (w *WshRpc) handleRequest(req *RpcMessage) {
w.registerResponseHandler(req.ReqId, respHandler) w.registerResponseHandler(req.ReqId, respHandler)
isAsync := false isAsync := false
defer func() { defer func() {
panicErr := panichandler.PanicHandler("handleRequest") panicErr := panichandler.PanicHandler("handleRequest", recover())
if panicErr != nil { if panicErr != nil {
respHandler.SendResponseError(panicErr) respHandler.SendResponseError(panicErr)
} }
if isAsync { if isAsync {
go func() { go func() {
defer panichandler.PanicHandler("handleRequest:finalize") defer func() {
panichandler.PanicHandler("handleRequest:finalize", recover())
}()
<-ctx.Done() <-ctx.Done()
respHandler.Finalize() respHandler.Finalize()
}() }()
@ -343,7 +345,9 @@ func (w *WshRpc) runServer() {
} }
if msg.IsRpcRequest() { if msg.IsRpcRequest() {
go func() { go func() {
defer panichandler.PanicHandler("handleRequest:goroutine") defer func() {
panichandler.PanicHandler("handleRequest:goroutine", recover())
}()
w.handleRequest(&msg) w.handleRequest(&msg)
}() }()
} else { } else {
@ -388,7 +392,9 @@ func (w *WshRpc) registerRpc(ctx context.Context, reqId string) chan *RpcMessage
Ctx: ctx, Ctx: ctx,
} }
go func() { go func() {
defer panichandler.PanicHandler("registerRpc:timeout") defer func() {
panichandler.PanicHandler("registerRpc:timeout", recover())
}()
<-ctx.Done() <-ctx.Done()
w.unregisterRpc(reqId, fmt.Errorf("EC-TIME: timeout waiting for response")) w.unregisterRpc(reqId, fmt.Errorf("EC-TIME: timeout waiting for response"))
}() }()
@ -458,7 +464,9 @@ func (handler *RpcRequestHandler) Context() context.Context {
} }
func (handler *RpcRequestHandler) SendCancel() { func (handler *RpcRequestHandler) SendCancel() {
defer panichandler.PanicHandler("SendCancel") defer func() {
panichandler.PanicHandler("SendCancel", recover())
}()
msg := &RpcMessage{ msg := &RpcMessage{
Cancel: true, Cancel: true,
ReqId: handler.reqId, ReqId: handler.reqId,
@ -563,7 +571,9 @@ func (handler *RpcResponseHandler) SendMessage(msg string) {
} }
func (handler *RpcResponseHandler) SendResponse(data any, done bool) error { func (handler *RpcResponseHandler) SendResponse(data any, done bool) error {
defer panichandler.PanicHandler("SendResponse") defer func() {
panichandler.PanicHandler("SendResponse", recover())
}()
if handler.reqId == "" { if handler.reqId == "" {
return nil // no response expected return nil // no response expected
} }
@ -588,7 +598,9 @@ func (handler *RpcResponseHandler) SendResponse(data any, done bool) error {
} }
func (handler *RpcResponseHandler) SendResponseError(err error) { func (handler *RpcResponseHandler) SendResponseError(err error) {
defer panichandler.PanicHandler("SendResponseError") defer func() {
panichandler.PanicHandler("SendResponseError", recover())
}()
if handler.reqId == "" || handler.done.Load() { if handler.reqId == "" || handler.done.Load() {
return return
} }
@ -637,7 +649,9 @@ func (w *WshRpc) SendComplexRequest(command string, data any, opts *wshrpc.RpcOp
if timeoutMs <= 0 { if timeoutMs <= 0 {
timeoutMs = DefaultTimeoutMs timeoutMs = DefaultTimeoutMs
} }
defer panichandler.PanicHandler("SendComplexRequest") defer func() {
panichandler.PanicHandler("SendComplexRequest", recover())
}()
if command == "" { if command == "" {
return nil, fmt.Errorf("command cannot be empty") return nil, fmt.Errorf("command cannot be empty")
} }

View File

@ -151,7 +151,7 @@ func installShutdownSignalHandlers(quiet bool) {
sigCh := make(chan os.Signal, 1) sigCh := make(chan os.Signal, 1)
signal.Notify(sigCh, syscall.SIGHUP, syscall.SIGTERM, syscall.SIGINT) signal.Notify(sigCh, syscall.SIGHUP, syscall.SIGTERM, syscall.SIGINT)
go func() { go func() {
defer panichandler.PanicHandlerNoTelemetry("installShutdownSignalHandlers") defer panichandler.PanicHandlerNoTelemetry("installShutdownSignalHandlers", recover())
for sig := range sigCh { for sig := range sigCh {
DoShutdown(fmt.Sprintf("got signal %v", sig), 1, quiet) DoShutdown(fmt.Sprintf("got signal %v", sig), 1, quiet)
break break
@ -200,7 +200,9 @@ func SetupTerminalRpcClient(serverImpl ServerImpl) (*WshRpc, io.Reader) {
ptyBuf := MakePtyBuffer(WaveServerOSCPrefix, os.Stdin, messageCh) ptyBuf := MakePtyBuffer(WaveServerOSCPrefix, os.Stdin, messageCh)
rpcClient := MakeWshRpc(messageCh, outputCh, wshrpc.RpcContext{}, serverImpl) rpcClient := MakeWshRpc(messageCh, outputCh, wshrpc.RpcContext{}, serverImpl)
go func() { go func() {
defer panichandler.PanicHandler("SetupTerminalRpcClient") defer func() {
panichandler.PanicHandler("SetupTerminalRpcClient", recover())
}()
for msg := range outputCh { for msg := range outputCh {
barr, err := EncodeWaveOSCBytes(WaveOSC, msg) barr, err := EncodeWaveOSCBytes(WaveOSC, msg)
if err != nil { if err != nil {
@ -221,7 +223,9 @@ func SetupPacketRpcClient(input io.Reader, output io.Writer, serverImpl ServerIm
rpcClient := MakeWshRpc(messageCh, outputCh, wshrpc.RpcContext{}, serverImpl) rpcClient := MakeWshRpc(messageCh, outputCh, wshrpc.RpcContext{}, serverImpl)
go packetparser.Parse(input, messageCh, rawCh) go packetparser.Parse(input, messageCh, rawCh)
go func() { go func() {
defer panichandler.PanicHandler("SetupPacketRpcClient:outputloop") defer func() {
panichandler.PanicHandler("SetupPacketRpcClient:outputloop", recover())
}()
for msg := range outputCh { for msg := range outputCh {
packetparser.WritePacket(output, msg) packetparser.WritePacket(output, msg)
} }
@ -234,7 +238,9 @@ func SetupConnRpcClient(conn net.Conn, serverImpl ServerImpl) (*WshRpc, chan err
outputCh := make(chan []byte, DefaultOutputChSize) outputCh := make(chan []byte, DefaultOutputChSize)
writeErrCh := make(chan error, 1) writeErrCh := make(chan error, 1)
go func() { go func() {
defer panichandler.PanicHandler("SetupConnRpcClient:AdaptOutputChToStream") defer func() {
panichandler.PanicHandler("SetupConnRpcClient:AdaptOutputChToStream", recover())
}()
writeErr := AdaptOutputChToStream(outputCh, conn) writeErr := AdaptOutputChToStream(outputCh, conn)
if writeErr != nil { if writeErr != nil {
writeErrCh <- writeErr writeErrCh <- writeErr
@ -242,7 +248,9 @@ func SetupConnRpcClient(conn net.Conn, serverImpl ServerImpl) (*WshRpc, chan err
} }
}() }()
go func() { go func() {
defer panichandler.PanicHandler("SetupConnRpcClient:AdaptStreamToMsgCh") defer func() {
panichandler.PanicHandler("SetupConnRpcClient:AdaptStreamToMsgCh", recover())
}()
// when input is closed, close the connection // when input is closed, close the connection
defer conn.Close() defer conn.Close()
AdaptStreamToMsgCh(conn, inputCh) AdaptStreamToMsgCh(conn, inputCh)
@ -270,7 +278,9 @@ func SetupDomainSocketRpcClient(sockName string, serverImpl ServerImpl) (*WshRpc
} }
rtn, errCh, err := SetupConnRpcClient(conn, serverImpl) rtn, errCh, err := SetupConnRpcClient(conn, serverImpl)
go func() { go func() {
defer panichandler.PanicHandler("SetupDomainSocketRpcClient:closeConn") defer func() {
panichandler.PanicHandler("SetupDomainSocketRpcClient:closeConn", recover())
}()
defer conn.Close() defer conn.Close()
err := <-errCh err := <-errCh
if err != nil && err != io.EOF { if err != nil && err != io.EOF {
@ -417,11 +427,15 @@ func HandleStdIOClient(logName string, input io.Reader, output io.Writer) {
proxy.DisposeRoutes() proxy.DisposeRoutes()
} }
go func() { go func() {
defer panichandler.PanicHandler("HandleStdIOClient:RunUnauthLoop") defer func() {
panichandler.PanicHandler("HandleStdIOClient:RunUnauthLoop", recover())
}()
proxy.RunUnauthLoop() proxy.RunUnauthLoop()
}() }()
go func() { go func() {
defer panichandler.PanicHandler("HandleStdIOClient:ToRemoteChLoop") defer func() {
panichandler.PanicHandler("HandleStdIOClient:ToRemoteChLoop", recover())
}()
defer closeDoneCh() defer closeDoneCh()
for msg := range proxy.ToRemoteCh { for msg := range proxy.ToRemoteCh {
err := packetparser.WritePacket(output, msg) err := packetparser.WritePacket(output, msg)
@ -432,7 +446,9 @@ func HandleStdIOClient(logName string, input io.Reader, output io.Writer) {
} }
}() }()
go func() { go func() {
defer panichandler.PanicHandler("HandleStdIOClient:RawChLoop") defer func() {
panichandler.PanicHandler("HandleStdIOClient:RawChLoop", recover())
}()
defer closeDoneCh() defer closeDoneCh()
for msg := range rawCh { for msg := range rawCh {
log.Printf("[%s:stdout] %s", logName, msg) log.Printf("[%s:stdout] %s", logName, msg)
@ -445,7 +461,9 @@ func handleDomainSocketClient(conn net.Conn) {
var routeIdContainer atomic.Pointer[string] var routeIdContainer atomic.Pointer[string]
proxy := MakeRpcProxy() proxy := MakeRpcProxy()
go func() { go func() {
defer panichandler.PanicHandler("handleDomainSocketClient:AdaptOutputChToStream") defer func() {
panichandler.PanicHandler("handleDomainSocketClient:AdaptOutputChToStream", recover())
}()
writeErr := AdaptOutputChToStream(proxy.ToRemoteCh, conn) writeErr := AdaptOutputChToStream(proxy.ToRemoteCh, conn)
if writeErr != nil { if writeErr != nil {
log.Printf("error writing to domain socket: %v\n", writeErr) log.Printf("error writing to domain socket: %v\n", writeErr)
@ -453,7 +471,9 @@ func handleDomainSocketClient(conn net.Conn) {
}() }()
go func() { go func() {
// when input is closed, close the connection // when input is closed, close the connection
defer panichandler.PanicHandler("handleDomainSocketClient:AdaptStreamToMsgCh") defer func() {
panichandler.PanicHandler("handleDomainSocketClient:AdaptStreamToMsgCh", recover())
}()
defer func() { defer func() {
conn.Close() conn.Close()
routeIdPtr := routeIdContainer.Load() routeIdPtr := routeIdContainer.Load()

View File

@ -223,7 +223,9 @@ func CpHostToRemote(ctx context.Context, client *Distro, sourcePath string, dest
return fmt.Errorf("cannot open local file %s to send to host: %v", sourcePath, err) return fmt.Errorf("cannot open local file %s to send to host: %v", sourcePath, err)
} }
go func() { go func() {
defer panichandler.PanicHandler("wslutil:cpHostToRemote:catStdin") defer func() {
panichandler.PanicHandler("wslutil:cpHostToRemote:catStdin", recover())
}()
io.Copy(catStdin, input) io.Copy(catStdin, input)
installStepCmds["cat"].Cancel() installStepCmds["cat"].Cancel()

View File

@ -236,7 +236,9 @@ func (conn *WslConn) StartConnServer() error {
}) })
// service the I/O // service the I/O
go func() { go func() {
defer panichandler.PanicHandler("wsl:StartConnServer:wait") defer func() {
panichandler.PanicHandler("wsl:StartConnServer:wait", recover())
}()
// wait for termination, clear the controller // wait for termination, clear the controller
defer conn.WithLock(func() { defer conn.WithLock(func() {
conn.ConnController = nil conn.ConnController = nil
@ -245,7 +247,9 @@ func (conn *WslConn) StartConnServer() error {
log.Printf("conn controller (%q) terminated: %v", conn.GetName(), waitErr) log.Printf("conn controller (%q) terminated: %v", conn.GetName(), waitErr)
}() }()
go func() { go func() {
defer panichandler.PanicHandler("wsl:StartConnServer:handleStdIOClient") defer func() {
panichandler.PanicHandler("wsl:StartConnServer:handleStdIOClient", recover())
}()
logName := fmt.Sprintf("conncontroller:%s", conn.GetName()) logName := fmt.Sprintf("conncontroller:%s", conn.GetName())
wshutil.HandleStdIOClient(logName, pipeRead, inputPipeWrite) wshutil.HandleStdIOClient(logName, pipeRead, inputPipeWrite)
}() }()

View File

@ -285,7 +285,9 @@ func DBDelete(ctx context.Context, otype string, id string) error {
return err return err
} }
go func() { go func() {
defer panichandler.PanicHandler("DBDelete:filestore.DeleteZone") defer func() {
panichandler.PanicHandler("DBDelete:filestore.DeleteZone", recover())
}()
// we spawn a go routine here because we don't want to reuse the DB connection // we spawn a go routine here because we don't want to reuse the DB connection
// since DBDelete is called in a transaction from DeleteTab // since DBDelete is called in a transaction from DeleteTab
deleteCtx, cancelFn := context.WithTimeout(context.Background(), 2*time.Second) deleteCtx, cancelFn := context.WithTimeout(context.Background(), 2*time.Second)