返回 DeepSeek-Reasonix
store.go
根目录 / internal / taskmonitor / store.go
1 package taskmonitor
2
3 import (
4 "context"
5 "errors"
6 "time"
7 )
8
9 // ErrStoreVersionConflict reports that a snapshot CAS lost to another writer.
10 // Callers may re-read and retry a derived update, or return a stable client
11 // conflict without parsing implementation-specific error text.
12 var ErrStoreVersionConflict = errors.New("task store version conflict")
13
14 // Store is the read-only query surface for task monitoring.
15 type Store interface {
16 ListTasks(ctx context.Context, projectDir string) ([]TaskSnapshot, error)
17 GetTask(ctx context.Context, projectDir string, taskID string) (*TaskSnapshot, error)
18 ListEvents(ctx context.Context, projectDir string, taskID string, afterSequence int) ([]TaskEvent, error)
19 }
20
21 // IdempotencyRecord captures the binding between an idempotency key and the
22 // operation it was used for.
23 type IdempotencyRecord struct {
24 Key string `json:"key"`
25 Op string `json:"op"`
26 TaskID string `json:"task_id"`
27 Version uint64 `json:"version"`
28 Pending bool `json:"pending,omitempty"`
29 ClaimedAt time.Time `json:"claimed_at,omitempty"`
30 }
31
32 // IdempotencyClaimer atomically reserves a key before a control operation
33 // performs any side effect. Pending claims can be finalized or released.
34 type IdempotencyClaimer interface {
35 ClaimIdempotency(ctx context.Context, projectDir string, r IdempotencyRecord) (*IdempotencyRecord, error)
36 FinalizeIdempotency(ctx context.Context, projectDir string, r IdempotencyRecord) error
37 ReleaseIdempotency(ctx context.Context, projectDir, key string) error
38 }
39
40 // WriteStore extends Store with atomic write operations for control
41 // commands, persistent idempotency, and event sequencing.
42 //
43 // Transaction ordering for control operations:
44 // 1. ClaimIdempotency — reserve the key before runtime/state side effects
45 // 2. SaveTask — persist state with version CAS
46 // 3. AppendAuditEvent — atomically assign sequence + write event
47 // 4. FinalizeIdempotency — mark the claim complete
48 //
49 // Steps 2-3 failures after a successful SaveTask leave the task in the new
50 // state with a potentially incomplete audit log. This is acceptable for a
51 // file-based store; a transactional store would provide stronger guarantees.
52 type WriteStore interface {
53 Store
54
55 // SaveTask atomically persists snap with version-based CAS.
56 SaveTask(ctx context.Context, projectDir string, snap TaskSnapshot) error
57
58 // RenewRuntimeLease extends an alive task lease only when ownerID still
59 // owns the persisted runtime generation. Implementations must read the raw
60 // stored snapshot rather than a liveness-reconciled observation.
61 RenewRuntimeLease(ctx context.Context, projectDir, taskID, ownerID string, leaseUntil time.Time) (bool, error)
62
63 // AppendAuditEvent atomically assigns the next monotonic sequence
64 // number and appends the event to taskID's event log. Implementations
65 // must be safe for concurrent use across processes.
66 AppendAuditEvent(ctx context.Context, projectDir string, ev TaskEvent) error
67
68 // CheckIdempotency returns the recorded key if it exists, or nil.
69 CheckIdempotency(ctx context.Context, projectDir string, key string) (*IdempotencyRecord, error)
70
71 // RecordIdempotency atomically claims key for r. If key already exists
72 // with identical parameters, it is a no-op. If key exists with different
73 // parameters, it must return an error. Implementations must be safe
74 // across process restarts.
75 RecordIdempotency(ctx context.Context, projectDir string, r IdempotencyRecord) error
76 }
77
77 lines GO