fix: order command controls after dispatch

This commit is contained in:
2026-09-11 08:56:00 +00:00
parent f6f900e597
commit 684981c235
13 changed files with 360 additions and 38 deletions
+18 -18
View File
@@ -159,7 +159,7 @@ func RunOnce(ctx context.Context, options RunnerOptions) error {
func runOnce(ctx context.Context, options RunnerOptions) (resultErr error) {
transport, err := options.Dial(ctx)
if err != nil {
return err
return fmt.Errorf("dial agent server: %w", err)
}
defer func() {
if closeErr := transport.Close(); resultErr == nil && closeErr != nil {
@@ -173,7 +173,7 @@ func runOnce(ctx context.Context, options RunnerOptions) (resultErr error) {
}
session, err := Handshake(ctx, transport, options.Hello, limits)
if err != nil {
return err
return fmt.Errorf("agent handshake: %w", err)
}
snapshot, err := options.Store.ReconcileSnapshot(ctx)
if err != nil {
@@ -181,7 +181,7 @@ func runOnce(ctx context.Context, options RunnerOptions) (resultErr error) {
}
result, err := Reconcile(ctx, transport, session, snapshot, limits)
if err != nil {
return err
return fmt.Errorf("exchange reconciliation: %w", err)
}
terminated, err := ApplyReconcileResult(ctx, options.Store, result, options.Now())
if err != nil {
@@ -190,16 +190,16 @@ func runOnce(ctx context.Context, options RunnerOptions) (resultErr error) {
for _, issue := range terminated {
if options.OnTerminate != nil {
if err := options.OnTerminate(ctx, issue); err != nil {
return err
return fmt.Errorf("terminate reconciled command %s: %w", issue, err)
}
}
}
sentEvents := make(map[domain.UUID]uint64)
if err := replayEvents(ctx, transport, options.Store, session, snapshot, limits, sentEvents); err != nil {
return err
return fmt.Errorf("replay client events: %w", err)
}
if err := sendCapacity(ctx, transport, session, options.Hello, snapshot, limits); err != nil {
return err
return fmt.Errorf("advertise client capacity: %w", err)
}
return serveActive(ctx, transport, options, session, sentEvents)
}
@@ -330,20 +330,20 @@ func serveActive(ctx context.Context, transport Transport, options RunnerOptions
case <-ctx.Done():
return nil
case err := <-readErrors:
return err
return fmt.Errorf("read active agent frame: %w", err)
case issue := <-options.EventReady:
if issue == (domain.UUID{}) {
continue
}
if err := flushEvents(ctx, transport, options.Store, session, issue, limits, sent); err != nil {
return err
return fmt.Errorf("flush ready command %s events: %w", issue, err)
}
continue
case encoded = <-frames:
}
envelope, err := agentproto.DecodeEnvelope(encoded, limits, rvboxv1.Platform_PLATFORM_WINDOWS)
if err != nil {
return err
return fmt.Errorf("decode active agent frame: %w", err)
}
if envelope.GetSessionId() != session.ID || envelope.GetSessionGeneration() != session.Generation {
return ErrProtocolHandshake
@@ -365,11 +365,11 @@ func serveActive(ctx context.Context, transport Transport, options RunnerOptions
}
case envelope.GetScriptChunk() != nil:
if err := handleScriptChunk(ctx, transport, options.Store, session, envelope.GetScriptChunk(), limits, options.Now, sent); err != nil {
return err
return fmt.Errorf("apply script chunk for %s: %w", envelope.GetScriptChunk().GetIssueUuid(), err)
}
case envelope.GetScriptCommit() != nil:
if err := handleScriptCommit(ctx, transport, options.Store, session, envelope.GetScriptCommit(), limits, options.Now, sent); err != nil {
return err
return fmt.Errorf("commit script for %s: %w", envelope.GetScriptCommit().GetIssueUuid(), err)
}
if options.OnScriptReady != nil {
issue, err := domain.ParseUUIDv7(envelope.GetScriptCommit().GetIssueUuid())
@@ -377,40 +377,40 @@ func serveActive(ctx context.Context, transport Transport, options RunnerOptions
return err
}
if err := options.OnScriptReady(ctx, session, issue); err != nil {
return err
return fmt.Errorf("start committed script %s: %w", issue, err)
}
}
case envelope.GetStdinWrite() != nil:
if options.OnStdin != nil {
if err := options.OnStdin(ctx, session, envelope.GetStdinWrite()); err != nil {
return err
return fmt.Errorf("append stdin for %s: %w", envelope.GetStdinWrite().GetIssueUuid(), err)
}
}
if issue, parseErr := domain.ParseUUIDv7(envelope.GetStdinWrite().GetIssueUuid()); parseErr == nil {
if err := flushEvents(ctx, transport, options.Store, session, issue, limits, sent); err != nil {
return err
return fmt.Errorf("flush stdin command %s events: %w", issue, err)
}
}
case envelope.GetCloseStdin() != nil:
if options.OnCloseStdin != nil {
if err := options.OnCloseStdin(ctx, session, envelope.GetCloseStdin()); err != nil {
return err
return fmt.Errorf("close stdin for %s: %w", envelope.GetCloseStdin().GetIssueUuid(), err)
}
}
if issue, parseErr := domain.ParseUUIDv7(envelope.GetCloseStdin().GetIssueUuid()); parseErr == nil {
if err := flushEvents(ctx, transport, options.Store, session, issue, limits, sent); err != nil {
return err
return fmt.Errorf("flush closed-stdin command %s events: %w", issue, err)
}
}
case envelope.GetSignalCommand() != nil:
if options.OnSignal != nil {
if err := options.OnSignal(ctx, session, envelope.GetSignalCommand()); err != nil {
return err
return fmt.Errorf("signal command %s: %w", envelope.GetSignalCommand().GetIssueUuid(), err)
}
}
if issue, parseErr := domain.ParseUUIDv7(envelope.GetSignalCommand().GetIssueUuid()); parseErr == nil {
if err := flushEvents(ctx, transport, options.Store, session, issue, limits, sent); err != nil {
return err
return fmt.Errorf("flush signalled command %s events: %w", issue, err)
}
}
case envelope.GetError() != nil: