(t *testing.T)
| 3688 | } |
| 3689 | |
| 3690 | func TestRecoverStaleChatsPeriodically(t *testing.T) { |
| 3691 | t.Parallel() |
| 3692 | |
| 3693 | db, ps := dbtestutil.NewDB(t) |
| 3694 | |
| 3695 | ctx := testutil.Context(t, testutil.WaitLong) |
| 3696 | user, org, model := seedChatDependencies(t, db) |
| 3697 | |
| 3698 | // Use a very short stale threshold so the periodic recovery |
| 3699 | // kicks in quickly during the test. |
| 3700 | staleAfter := 500 * time.Millisecond |
| 3701 | |
| 3702 | // Create a chat and simulate a dead worker by setting the chat |
| 3703 | // to running with a heartbeat in the past. |
| 3704 | deadWorkerID := uuid.New() |
| 3705 | chat := dbgen.Chat(t, db, database.Chat{ |
| 3706 | OrganizationID: org.ID, |
| 3707 | OwnerID: user.ID, |
| 3708 | Title: "stale-recovery-periodic", |
| 3709 | LastModelConfigID: model.ID, |
| 3710 | }) |
| 3711 | |
| 3712 | _, err := db.UpdateChatStatus(ctx, database.UpdateChatStatusParams{ |
| 3713 | ID: chat.ID, |
| 3714 | Status: database.ChatStatusRunning, |
| 3715 | WorkerID: uuid.NullUUID{UUID: deadWorkerID, Valid: true}, |
| 3716 | StartedAt: sql.NullTime{Time: time.Now().Add(-time.Hour), Valid: true}, |
| 3717 | HeartbeatAt: sql.NullTime{Time: time.Now().Add(-time.Hour), Valid: true}, |
| 3718 | }) |
| 3719 | require.NoError(t, err) |
| 3720 | |
| 3721 | // Start a new replica. Its startup recovery will reset the |
| 3722 | // chat (since the heartbeat is old), but the key point is that |
| 3723 | // the periodic loop also recovers newly-stale chats. |
| 3724 | logger := slogtest.Make(t, &slogtest.Options{IgnoreErrors: true}) |
| 3725 | server := chatd.New(chatd.Config{ |
| 3726 | Logger: logger, |
| 3727 | Database: db, |
| 3728 | ReplicaID: uuid.New(), |
| 3729 | Pubsub: ps, |
| 3730 | PendingChatAcquireInterval: testutil.WaitLong, |
| 3731 | InFlightChatStaleAfter: staleAfter, |
| 3732 | }) |
| 3733 | server.Start() |
| 3734 | t.Cleanup(func() { |
| 3735 | require.NoError(t, server.Close()) |
| 3736 | }) |
| 3737 | |
| 3738 | // The startup recovery should have already reset our stale |
| 3739 | // chat. |
| 3740 | require.Eventually(t, func() bool { |
| 3741 | fromDB, err := db.GetChatByID(ctx, chat.ID) |
| 3742 | if err != nil { |
| 3743 | return false |
| 3744 | } |
| 3745 | return fromDB.Status == database.ChatStatusPending |
| 3746 | }, testutil.WaitMedium, testutil.IntervalFast) |
| 3747 |
nothing calls this directly
no test coverage detected