Documentation
¶
Index ¶
Constants ¶
const ( // NoTokenBackoff is the backoff duration applied to rows // whose owner has no linked external-auth token. Much longer // than DiffStatusTTL because the user must manually link // their account before retrying is useful. NoTokenBackoff = 10 * time.Minute // NoPRBackoff is the backoff applied when a branch has no // associated pull request yet. Kept short so that PRs created // shortly after a push (e.g. via `gh pr create`) are // discovered quickly instead of waiting for the 5-minute // acquisition lock to expire. NoPRBackoff = 15 * time.Second // NoPRRetryWindow is how long after MarkStale the worker // applies the short NoPRBackoff. Outside this window the // worker lets the 5-minute acquisition lock serve as the // natural retry interval, avoiding indefinite fast-polling // for branches that never receive a PR. // // Together with NoPRBackoff this bounds the number of // GitHub API calls to ~NoPRRetryWindow/NoPRBackoff (≈8) // per push. Keep both values in sync when adjusting. NoPRRetryWindow = 2 * time.Minute )
const ( // DiffStatusTTL is how long a successfully refreshed // diff status remains fresh before becoming stale again. DiffStatusTTL = 120 * time.Second )
Variables ¶
var ErrNoTokenAvailable error = errors.New("no token available")
var ErrRateLimitSkipped error = errors.New("skipped due to rate limit")
ErrRateLimitSkipped indicates that a row was skipped because a prior request in the same group hit a rate limit.
Functions ¶
This section is empty.
Types ¶
type MarkStaleParams ¶
type MarkStaleParams struct {
WorkspaceID uuid.UUID
Branch string
Origin string
// ChatID, when set, targets a single chat instead of
// broadcasting to every chat on the workspace.
ChatID uuid.UUID
}
MarkStaleParams holds the arguments for Worker.MarkStale.
type ProviderResolver ¶
type ProviderResolver func(origin string) gitprovider.Provider
ProviderResolver maps a git remote origin to the gitprovider that handles it. Returns nil if no provider matches.
type PublishDiffStatusChangeFunc ¶
EventPublisher notifies the frontend of diff status changes.
type RefreshRequest ¶
type RefreshRequest struct {
Row database.ChatDiffStatus
OwnerID uuid.UUID
}
RefreshRequest pairs a stale row with the chat owner who holds the git token needed for API calls.
type RefreshResult ¶
type RefreshResult struct {
Request RefreshRequest
Params *database.UpsertChatDiffStatusParams
Error error
}
RefreshResult is the outcome for a single row.
- Params != nil, Error == nil → success, caller should upsert.
- Params == nil, Error == nil → no PR yet, caller should skip.
- Params == nil, Error != nil → row-level failure.
type Refresher ¶
type Refresher struct {
// contains filtered or unexported fields
}
Refresher contains the stateless business logic for fetching fresh PR data from a git provider given a stale database.ChatDiffStatus row.
func NewRefresher ¶
func NewRefresher( providers ProviderResolver, tokens TokenResolver, logger slog.Logger, clock quartz.Clock, opts ...RefresherOption, ) *Refresher
NewRefresher creates a Refresher with the given dependency functions.
func (*Refresher) Refresh ¶
func (r *Refresher) Refresh( ctx context.Context, requests []RefreshRequest, ) ([]RefreshResult, error)
Refresh fetches fresh PR data for a batch of stale rows. Rows are grouped internally by (ownerID, origin) so that provider and token resolution happen once per group. HTTP calls within and across groups run concurrently, bounded by the Refresher's concurrency limit.
A top-level error is returned only when the entire batch fails catastrophically. Per-row outcomes are in the returned RefreshResult slice (one per input request, same order).
type RefresherOption ¶
type RefresherOption func(*Refresher)
RefresherOption configures a Refresher.
func WithConcurrency ¶
func WithConcurrency(n int) RefresherOption
WithConcurrency sets the maximum number of concurrent HTTP calls per Refresh batch. Defaults to defaultConcurrency.
type Store ¶
type Store interface {
AcquireStaleChatDiffStatuses(
ctx context.Context, limitVal int32,
) ([]database.AcquireStaleChatDiffStatusesRow, error)
BackoffChatDiffStatus(
ctx context.Context, arg database.BackoffChatDiffStatusParams,
) error
UpsertChatDiffStatus(
ctx context.Context, arg database.UpsertChatDiffStatusParams,
) (database.ChatDiffStatus, error)
UpsertChatDiffStatusReference(
ctx context.Context, arg database.UpsertChatDiffStatusReferenceParams,
) (database.ChatDiffStatus, error)
GetChatsByWorkspaceIDs(
ctx context.Context, ids []uuid.UUID,
) ([]database.Chat, error)
}
Store is the narrow DB interface the Worker needs.
type TokenResolver ¶
TokenResolver obtains the user's git access token for a given remote origin. Should return nil if no token is available, in which case ErrNoTokenAvailable will be returned.
type Worker ¶
type Worker struct {
// contains filtered or unexported fields
}
Worker is a background loop that periodically refreshes stale chat diff statuses by delegating to a Refresher.
func NewWorker ¶
func NewWorker( store Store, refresher *Refresher, publisher PublishDiffStatusChangeFunc, clock quartz.Clock, logger slog.Logger, opts ...WorkerOption, ) *Worker
NewWorker creates a Worker with default batch size and interval.
func (*Worker) Done ¶
func (w *Worker) Done() <-chan struct{}
Done returns a channel that is closed when the worker exits.
func (*Worker) MarkStale ¶
func (w *Worker) MarkStale(ctx context.Context, p MarkStaleParams)
MarkStale persists the git ref for a chat (or all chats on a workspace when no ChatID is provided), setting stale_at to the past so the next tick picks them up. Publishes a diff status event for each affected chat. Called from workspaceagents handlers. No goroutines spawned.
func (*Worker) RefreshChat ¶
func (w *Worker) RefreshChat( ctx context.Context, row database.ChatDiffStatus, ownerID uuid.UUID, ) (*database.ChatDiffStatus, error)
RefreshChat synchronously refreshes a single chat's diff status using the same Refresher pipeline as the background worker. Returns nil, nil when no PR exists yet for the branch. Called from HTTP handlers for instant feedback.
type WorkerOption ¶
type WorkerOption func(*Worker)
WorkerOption configures a Worker.
func WithTickTimeout ¶
func WithTickTimeout(d time.Duration) WorkerOption
WithTickTimeout sets the maximum duration for a single tick.