mirror of
https://github.com/pocketbase/pocketbase.git
synced 2026-10-23 22:40:24 +02:00
fixed unhandled panic and wrapped all internal goroutines
This commit is contained in:
1 parent
a6deb6ab90
commit
30b4184305
11 files changed
+76
-22
No files matched your search
+4
-2
@@ -13,6 +13,8 @@ import (
|
||||
"fmt"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/pocketbase/pocketbase/tools/routine"
|
||||
)
|
||||
|
||||
type job struct {
|
||||
@@ -170,7 +172,7 @@ func (c *Cron) Start() {
|
||||
c.runDue(time.Now())
|
||||
|
||||
// run after each tick
|
||||
go func() {
|
||||
routine.FireAndForget(func() {
|
||||
for {
|
||||
select {
|
||||
case <-c.tickerDone:
|
||||
@@ -179,7 +181,7 @@ func (c *Cron) Start() {
|
||||
c.runDue(t)
|
||||
}
|
||||
}
|
||||
}()
|
||||
})
|
||||
})
|
||||
c.Unlock()
|
||||
}
|
||||
|
||||
@@ -85,6 +85,7 @@ import (
|
||||
s3managerv2 "github.com/aws/aws-sdk-go-v2/feature/s3/manager"
|
||||
s3v2 "github.com/aws/aws-sdk-go-v2/service/s3"
|
||||
typesv2 "github.com/aws/aws-sdk-go-v2/service/s3/types"
|
||||
"github.com/pocketbase/pocketbase/tools/routine"
|
||||
|
||||
"github.com/aws/smithy-go"
|
||||
"gocloud.dev/blob"
|
||||
@@ -362,7 +363,7 @@ func (w *writer) Upload(r io.Reader) error {
|
||||
// error uploading to S3.
|
||||
func (w *writer) open(r io.Reader, closePipeOnError bool) {
|
||||
// This goroutine will keep running until Close, unless there's an error.
|
||||
go func() {
|
||||
routine.FireAndForget(func() {
|
||||
defer close(w.donec)
|
||||
|
||||
if r == nil {
|
||||
@@ -379,7 +380,7 @@ func (w *writer) open(r io.Reader, closePipeOnError bool) {
|
||||
}
|
||||
w.err = err
|
||||
}
|
||||
}()
|
||||
})
|
||||
}
|
||||
|
||||
// Close completes the writer and closes it. Any error occurring during write
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package routine
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"runtime/debug"
|
||||
"sync"
|
||||
@@ -30,3 +31,17 @@ func FireAndForget(f func(), wg ...*sync.WaitGroup) {
|
||||
f()
|
||||
}()
|
||||
}
|
||||
|
||||
// SafeWrap wraps the provided function with auto panic recover handling
|
||||
// and returns any eventual panic as regular error.
|
||||
func SafeWrap(f func() error) func() error {
|
||||
return func() (err error) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
err = fmt.Errorf("[SafeWrap] recovered from panic: %v", r)
|
||||
}
|
||||
}()
|
||||
|
||||
return f()
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package routine_test
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
@@ -12,7 +13,7 @@ func TestFireAndForget(t *testing.T) {
|
||||
|
||||
fn := func() {
|
||||
called = true
|
||||
panic("test")
|
||||
panic("test_recover")
|
||||
}
|
||||
|
||||
wg := &sync.WaitGroup{}
|
||||
@@ -22,6 +23,29 @@ func TestFireAndForget(t *testing.T) {
|
||||
wg.Wait()
|
||||
|
||||
if !called {
|
||||
t.Error("Expected fn to be called.")
|
||||
t.Fatal("Expected fn to be called.")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSafeWrap(t *testing.T) {
|
||||
called := false
|
||||
|
||||
fn := func() error {
|
||||
called = true
|
||||
panic("test_recover")
|
||||
}
|
||||
|
||||
err := routine.SafeWrap(fn)()
|
||||
|
||||
if !called {
|
||||
t.Fatal("Expected fn to be called.")
|
||||
}
|
||||
|
||||
if err == nil {
|
||||
t.Fatal("Expected fn panic to be converted to error")
|
||||
}
|
||||
|
||||
if !strings.Contains(err.Error(), "test_recover") {
|
||||
t.Fatal("Expected the returned error to contain the recovered panic value")
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"strconv"
|
||||
|
||||
"github.com/pocketbase/dbx"
|
||||
"github.com/pocketbase/pocketbase/tools/routine"
|
||||
"golang.org/x/sync/errgroup"
|
||||
)
|
||||
|
||||
@@ -268,8 +269,8 @@ func (s *Provider) Exec(items any) (*Result, error) {
|
||||
// execute the 2 queries concurrently
|
||||
errg := new(errgroup.Group)
|
||||
errg.SetLimit(2)
|
||||
errg.Go(countExec)
|
||||
errg.Go(modelsExec)
|
||||
errg.Go(routine.SafeWrap(countExec))
|
||||
errg.Go(routine.SafeWrap(modelsExec))
|
||||
if err := errg.Wait(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user