heartbeatTick issues a single batch UPDATE for all running chats owned by this worker. Chats missing from the result set are interrupted (stolen by another replica or already completed).
(ctx context.Context)
| 4848 | // owned by this worker. Chats missing from the result set are |
| 4849 | // interrupted (stolen by another replica or already completed). |
| 4850 | func (p *Server) heartbeatTick(ctx context.Context) { |
| 4851 | // Snapshot the registry under the lock. |
| 4852 | p.heartbeatMu.Lock() |
| 4853 | snapshot := maps.Clone(p.heartbeatRegistry) |
| 4854 | p.heartbeatMu.Unlock() |
| 4855 | |
| 4856 | if len(snapshot) == 0 { |
| 4857 | return |
| 4858 | } |
| 4859 | |
| 4860 | // Collect the IDs we believe we own. |
| 4861 | ids := slices.Collect(maps.Keys(snapshot)) |
| 4862 | |
| 4863 | //nolint:gocritic // AsChatd provides narrowly-scoped daemon |
| 4864 | // access for batch-updating heartbeats. |
| 4865 | chatdCtx := dbauthz.AsChatd(ctx) |
| 4866 | updatedIDs, err := p.db.UpdateChatHeartbeats(chatdCtx, database.UpdateChatHeartbeatsParams{ |
| 4867 | IDs: ids, |
| 4868 | WorkerID: p.workerID, |
| 4869 | Now: p.clock.Now(), |
| 4870 | }) |
| 4871 | if err != nil { |
| 4872 | p.logger.Error(ctx, "batch heartbeat failed", slog.Error(err)) |
| 4873 | return |
| 4874 | } |
| 4875 | |
| 4876 | // Build a set of IDs that were successfully updated. |
| 4877 | updated := make(map[uuid.UUID]struct{}, len(updatedIDs)) |
| 4878 | for _, id := range updatedIDs { |
| 4879 | updated[id] = struct{}{} |
| 4880 | } |
| 4881 | |
| 4882 | // Interrupt registered chats that were not in the result |
| 4883 | // (stolen by another replica or already completed). |
| 4884 | for id, entry := range snapshot { |
| 4885 | if _, ok := updated[id]; !ok { |
| 4886 | entry.logger.Warn(ctx, "chat not in batch heartbeat result, interrupting") |
| 4887 | entry.cancelWithCause(chatloop.ErrInterrupted) |
| 4888 | continue |
| 4889 | } |
| 4890 | // Bump workspace usage for surviving chats. |
| 4891 | newWsID := p.trackWorkspaceUsage(ctx, entry.chatID, entry.workspaceID, entry.logger) |
| 4892 | // Update workspace ID in the registry for next tick. |
| 4893 | p.heartbeatMu.Lock() |
| 4894 | if current, exists := p.heartbeatRegistry[id]; exists { |
| 4895 | current.workspaceID = newWsID |
| 4896 | } |
| 4897 | p.heartbeatMu.Unlock() |
| 4898 | } |
| 4899 | } |
| 4900 | |
| 4901 | // streamSubscriberControlFetchContext keeps a control-path lookup tied to the |
| 4902 | // requesting subscriber while applying a fallback timeout when the caller has |