internal/memory/memory_remember/manager.go
Every run of the remember text pipeline is executed by one goroutine, the remember manager. The HTTP handlers (POST /v1/gb/remember, POST /v1/gb/eval/remember), and anything else that wants text remembered, do not call memory_remember.Remember: they send the manager a request. For now the manager serializes the runs: it takes the next request only when the previous run is over, so two runs never write at the same time.
Images (image in the request) are a different pipeline, have no run log, and are still remembered in the handler.
Requests
Submitreturns as soon as the request is queued, with the run ID: the ID of the run’s row ingb_remember_runs(the run log). The row is created bySubmit, so the ID exists before the run starts.Manager.Status(ctx, runID)reads the row later: its status, stages and error. It also fails at once, with nothing queued, for a request whose user, dataset or kind is invalid, or if the manager is closed (ErrManagerClosed).Outcomeis the completion channel, optional. The sender makes it, with a capacity of at least 1, and the manager sends oneOutcometo it when the run is over: theResultofRememberor its error. The handlers block on it, so for the client the call is still synchronous. The manager never blocks on it. Without it the request is fire and forget: pass a context that outlives the caller (context.WithoutCancel) and look at the run log.Ctxis the context of the run. A request whose context is done while it waits fails without running; a run in progress is cancelled with it (the handlers pass the request’s context, so a client that leaves cancels its run).
Queued runs
BetweenSubmit and the start of the run the row is already in the table, with status started and every stage not_started (the schema has no status for a queued run, and adding one would break existing databases). When the run begins the row is overwritten with its parameters and start time. A run that never starts (cancelled in the queue, or the manager closing) is marked failed with the reason.
The queue
The queue is two operations,enqueue and dequeue, which are the only places the manager touches it. By default it is a Go channel (256 runs; Submit blocks when it is full). An embedder with a queue system of its own can supply the operations as callbacks:
- The queue carries only the run ID. The request itself (its context, options and channels cannot be serialized) stays in the memory of the process, so the process that enqueues an ID must be the one that dequeues it; the external queue gives the queueing, persistence and ordering. A dequeued ID that is not a pending request of the process (left over from an earlier one) is logged and skipped.
Enqueuemay block, but must return when its context is done (the request’s or the manager’s); if it fails,Submitfails with its error and the run is markedfailed.Dequeuemust block until a run is available, and return when its context is done. An error while the manager is running is logged, and it is tried again after a second.
Shutdown
When the context of the manager is done, the run in progress is cancelled, every request that is still waiting fails withErrManagerClosed (its run is marked failed and its Outcome is sent), and Submit returns ErrManagerClosed. Manager.Wait() blocks until the goroutine has returned. The server stops the manager after the graceful HTTP shutdown, so requests in progress get their time first.