reparse

package
v0.2.4 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 2, 2026 License: AGPL-3.0 Imports: 8 Imported by: 0

Documentation

Overview

Package reparse is the self-healing reparse backbone: one service that rebuilds the parsed projection of stored sessions from their raw bytes, driven from three places that must never diverge: the server's startup epoch check, the admin Reparse button, and the akari-server reparse CLI. Centralizing the loop here (it used to be inline in the CLI) means all three share the same in-process guard, the same cross-process advisory lock, the same progress reporting, and the same post-reparse blob sweep.

A reparse rebuilds in place but atomically per session: store.ReparseSession clears and replays each session in one transaction, so a reader never sees that session empty or half rebuilt (it reads the old projection until the new one commits). What is not atomic is the corpus as a whole: while the loop works through sessions, a cross-session view (the overview, the session list) can briefly mix already-rebuilt and not-yet-rebuilt sessions. The HTTP layer gates the parsed UI for the duration so it shows progress rather than that transient mix. The gate is best-effort: a request can still race a reparse that starts mid-render and read a mixed aggregate, which is acceptable because every individual session stays consistent (no empty or half-built rows). A future improvement could build a shadow projection and swap it atomically across the whole corpus, removing the gate.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Options

type Options struct {
	// Agent limits the reparse to one agent (claude|codex|pi); empty reparses all.
	// A partial (agent-filtered) reparse never advances the stored epoch, since it
	// does not bring the whole corpus up to the current parser output.
	Agent string
	// Force marks an operator-initiated run (the CLI or the admin button) as opposed
	// to the startup auto-run. It is informational (it only flavors the log line):
	// the service runs whenever Trigger or Run is called, gated only by the in-process
	// guard and the advisory lock.
	Force bool
}

Options selects what a reparse covers.

type Result

type Result struct {
	Status
	// SweptBlobs is how many orphaned CAS blobs the post-reparse sweep reclaimed.
	SweptBlobs int
}

Result is the outcome of a synchronous reparse, for the CLI to report.

type Service

type Service struct {
	// contains filtered or unexported fields
}

Service runs reparses for one akari-server process. Exactly one reparse runs at a time within the process (the running flag), and at most one across processes (a Postgres advisory lock).

func New

func New(baseCtx context.Context, st *store.Store) *Service

New builds a Service. baseCtx should be the server's root context so background reparses (the startup auto-run and the admin button) are cancelled on shutdown; the CLI passes context.Background() to Run directly and does not rely on it.

func (*Service) FleetStatus

func (s *Service) FleetStatus(ctx context.Context) Status

FleetStatus is Status with InProgress widened to reflect a reparse running on any instance, not just this process. It is what the UI gate and the status endpoint read, so a server that is not itself reparsing still gates its parsed pages while another instance rebuilds the shared projection. The progress counts stay this process's: an observing instance reports the gate without counts, which the UI renders as an indeterminate bar.

func (*Service) Run

func (s *Service) Run(ctx context.Context, opts Options) (Result, error)

Run reparses synchronously and returns the result, for the CLI. It honors the same in-process guard and advisory lock as Trigger.

func (*Service) SetProgressHook

func (s *Service) SetProgressHook(fn func(Status))

SetProgressHook registers a callback invoked with the latest Status whenever it changes, so the HTTP layer can push progress over SSE. It is meant to be set once at construction, before any reparse runs.

func (*Service) SetStatusForTest

func (s *Service) SetStatusForTest(st Status)

SetStatusForTest overrides the reported status without running a reparse. It exists so tests in other packages (the HTTP gating tests) can force an in-progress state and exercise the gate; it is not used in production.

func (*Service) Status

func (s *Service) Status() Status

Status returns the current reparse status.

func (*Service) Trigger

func (s *Service) Trigger(opts Options) Status

Trigger starts a reparse in the background and returns immediately with the current status. If one is already running it is a no-op that returns the running status rather than starting a second. The background run uses the service's base context, so it survives the request that started it and is cancelled on shutdown.

func (*Service) Wait

func (s *Service) Wait()

Wait blocks until no reparse is running. The server calls it on shutdown, after cancelling the root context (which stops the reparse loop), so an in-flight reparse winds down cleanly before the connection pool closes.

type Status

type Status struct {
	// InProgress is true from the moment a reparse is accepted until it finishes,
	// including the brief window before the advisory lock is resolved. The parsed UI
	// gates on it.
	InProgress bool `json:"in_progress"`
	// Done is the number of sessions processed so far (successes plus failures),
	// Total the number to process, Failed the subset that errored. Done/Total drive
	// the progress bar.
	Done   int `json:"done"`
	Total  int `json:"total"`
	Failed int `json:"failed"`
	// StartedAt is when the current (or last) reparse began.
	StartedAt time.Time `json:"started_at,omitempty"`
}

Status is a snapshot of the current (or last) reparse. It is what the HTTP status endpoint and the SSE progress stream serialize, so its JSON tags are the wire contract the frontend reads.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL