Skip to content

Commit d5166bc

Browse files
committed
fix: race condition
1 parent bbb4dd4 commit d5166bc

File tree

4 files changed

+34
-25
lines changed

4 files changed

+34
-25
lines changed

.github/workflows/go.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ jobs:
9393
TEST_INDEX_HTML_URL: ${{ secrets.TEST_INDEX_HTML_URL }}
9494
TEST_SENTRY_DSN: ${{ secrets.TEST_SENTRY_DSN }}
9595
TEST_KEY_FILE_LOCATION: ${{ secrets.TEST_KEY_FILE_LOCATION }}
96-
run: go test -v -cover -coverprofile=coverage.txt -covermode=atomic ./...
96+
run: go test -race -v -cover -coverprofile=coverage.txt -covermode=atomic ./...
9797

9898
- name: Upload coverage reports to Codecov
9999
if: github.event_name == 'push' && github.ref == 'refs/heads/main'

database/dbConnect.go

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"context"
77
"database/sql"
88
"fmt"
9+
"sync"
910
"time"
1011

1112
"github.com/pilinux/gorest/config"
@@ -50,6 +51,9 @@ var RedisConnTTL int
5051
// mongoClient holds the MongoDB client connection instance.
5152
var mongoClient *mongo.Client
5253

54+
// protect CloseAllDB from concurrent calls
55+
var closeAllOnce sync.Once
56+
5357
// InitDB initializes the database connection.
5458
func InitDB() *gorm.DB {
5559
var db = dbClient
@@ -309,22 +313,24 @@ func GetMongo() *mongo.Client {
309313

310314
// CloseAllDB closes all database connections.
311315
func CloseAllDB() error {
312-
err := CloseSQL()
313-
if err != nil {
314-
return err
315-
}
316-
317-
err = CloseRedis()
318-
if err != nil {
319-
return err
320-
}
316+
var err error
317+
closeAllOnce.Do(func() {
318+
err = CloseSQL()
319+
if err != nil {
320+
return
321+
}
321322

322-
err = CloseMongo()
323-
if err != nil {
324-
return err
325-
}
323+
err = CloseRedis()
324+
if err != nil {
325+
return
326+
}
326327

327-
return nil
328+
err = CloseMongo()
329+
if err != nil {
330+
return
331+
}
332+
})
333+
return err
328334
}
329335

330336
// CloseSQL closes the SQL database connection.

lib/server/shutdown.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ func GracefulShutdown(srv *http.Server, timeout time.Duration, done chan struct{
1818
// create context that listens for the interrupt signal from the OS
1919
sigCh := make(chan os.Signal, 1)
2020
signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM)
21+
defer signal.Stop(sigCh)
2122

2223
sig := <-sigCh
2324
log.Printf("signal %v received: starting graceful shutdown with timeout %v\n", sig, timeout)

lib/server/shutdown_test.go

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -159,13 +159,13 @@ func TestGracefulShutdown_SuccessWithDBFail(t *testing.T) {
159159
return expectedErr
160160
}
161161

162-
// channel to signal shutdown completion
162+
// channel to signal shutdown completion and to receive shutdown error
163163
done := make(chan struct{})
164-
var shutdownErr error
164+
errCh := make(chan error, 1)
165165

166-
// run GracefulShutdown with the failing closeDB function
166+
// run GracefulShutdown with the failing closeDB function and send error on channel
167167
go func() {
168-
shutdownErr = server.GracefulShutdown(srv, 5*time.Second, done, closeDB)
168+
errCh <- server.GracefulShutdown(srv, 5*time.Second, done, closeDB)
169169
}()
170170

171171
// send SIGINT after 1 second
@@ -179,7 +179,8 @@ func TestGracefulShutdown_SuccessWithDBFail(t *testing.T) {
179179
t.Fatal("shutdown did not complete within 10 seconds")
180180
}
181181

182-
// verify that the closeDB error is returned
182+
// receive and verify that the closeDB error is returned
183+
shutdownErr := <-errCh
183184
if shutdownErr == nil {
184185
t.Error("expected an error, got nil")
185186
} else if !errors.Is(shutdownErr, expectedErr) {
@@ -225,13 +226,13 @@ func TestGracefulShutdown_TimeoutForceCloseSuccess(t *testing.T) {
225226
// wait briefly to ensure the request starts
226227
time.Sleep(500 * time.Millisecond)
227228

228-
// channel to signal shutdown completion
229+
// channel to signal shutdown completion and to receive shutdown error
229230
done := make(chan struct{})
230-
var shutdownErr error
231+
errCh := make(chan error, 1)
231232

232-
// run GracefulShutdown with a 2-second timeout
233+
// run GracefulShutdown with a 2-second timeout and send error on channel
233234
go func() {
234-
shutdownErr = server.GracefulShutdown(srv, 2*time.Second, done)
235+
errCh <- server.GracefulShutdown(srv, 2*time.Second, done)
235236
}()
236237

237238
// send SIGINT after 1 second, while the handler is still sleeping
@@ -245,7 +246,8 @@ func TestGracefulShutdown_TimeoutForceCloseSuccess(t *testing.T) {
245246
t.Fatal("shutdown did not complete within 10 seconds")
246247
}
247248

248-
// verify that the error is context.DeadlineExceeded
249+
// receive and verify that the error is context.DeadlineExceeded
250+
shutdownErr := <-errCh
249251
if !errors.Is(shutdownErr, context.DeadlineExceeded) {
250252
t.Errorf("expected context.DeadlineExceeded, got %v", shutdownErr)
251253
}

0 commit comments

Comments
 (0)