TestDB_Close_Timeout tests timeout handling during close
(t *testing.T)
| 1041 | |
| 1042 | // TestDB_Close_Timeout tests timeout handling during close |
| 1043 | func TestDB_Close_Timeout(t *testing.T) { |
| 1044 | r := require.New(t) |
| 1045 | opts := DefaultOptions |
| 1046 | opts.Dir = filepath.Join(t.TempDir(), "test-close-timeout") |
| 1047 | defer func() { _ = os.RemoveAll(opts.Dir) }() |
| 1048 | |
| 1049 | db, err := Open(opts) |
| 1050 | require.NoError(t, err) |
| 1051 | require.NotNil(t, db) |
| 1052 | |
| 1053 | // Configure a short shutdown timeout |
| 1054 | db.statusMgr.config.ShutdownTimeout = 1 * time.Second |
| 1055 | |
| 1056 | bucket := "test_bucket" |
| 1057 | err = db.Update(func(tx *Tx) error { |
| 1058 | return tx.NewBucket(DataStructureBTree, bucket) |
| 1059 | }) |
| 1060 | require.NoError(t, err) |
| 1061 | |
| 1062 | // Start a long-running transaction that exceeds timeout |
| 1063 | txStarted := make(chan struct{}) |
| 1064 | txDone := make(chan struct{}) |
| 1065 | |
| 1066 | go func() { |
| 1067 | _ = db.Update(func(tx *Tx) error { |
| 1068 | close(txStarted) |
| 1069 | // Sleep longer than shutdown timeout |
| 1070 | time.Sleep(3 * time.Second) |
| 1071 | return tx.Put(bucket, []byte("key1"), []byte("value"), Persistent) |
| 1072 | }) |
| 1073 | close(txDone) |
| 1074 | }() |
| 1075 | |
| 1076 | // Wait for transaction to start |
| 1077 | <-txStarted |
| 1078 | time.Sleep(100 * time.Millisecond) // Ensure tx is active |
| 1079 | |
| 1080 | // Close should timeout and force shutdown |
| 1081 | closeStartTime := time.Now() |
| 1082 | err = db.Close() |
| 1083 | closeDuration := time.Since(closeStartTime) |
| 1084 | |
| 1085 | require.Error(t, err, "Close should surface shutdown timeout") |
| 1086 | // Close should complete within reasonable time (timeout + buffer) |
| 1087 | // The important thing is it doesn't hang forever |
| 1088 | require.Less(t, closeDuration, 3*time.Second, "Close should timeout and not wait forever") |
| 1089 | |
| 1090 | // Database should be closed even if timeout occurred |
| 1091 | require.True(t, db.IsClose()) |
| 1092 | require.True(t, db.statusMgr.isClosed()) |
| 1093 | |
| 1094 | // Wait for background transaction to finish |
| 1095 | select { |
| 1096 | case <-txDone: |
| 1097 | case <-time.After(5 * time.Second): |
| 1098 | // Transaction may still be running, that's ok |
| 1099 | } |
| 1100 |