MCPcopy Create free account
hub / github.com/Mnexa-AI/e2a / Claim

Method Claim

internal/idempotency/store.go:155–238  ·  view source on GitHub ↗

Claim atomically reserves (userID, key) for the caller. The outcome determines what the HTTP layer should do next: - OutcomeAcquired → run the side effect, then Complete on success or Release on caller-side abort. - OutcomeReplay → write Cached to the response, do NOT re-run the side effect. - Ou

(ctx context.Context, userID, key, path, bodyHash string)

Source from the content-addressed store, hash-verified

153// lock and the loser sees a non-stale in_progress on its follow-up
154// read.
155func (s *Store) Claim(ctx context.Context, userID, key, path, bodyHash string) (ClaimResult, error) {
156 if userID == "" {
157 return ClaimResult{}, errors.New("idempotency: userID required")
158 }
159 if key == "" {
160 return ClaimResult{}, errors.New("idempotency: key required")
161 }
162
163 staleSecs := int(StaleClaimWindow.Seconds())
164
165 // Atomic claim path. Returns a row iff we own the slot — either as
166 // a fresh INSERT, or as a stale-takeover where the DO UPDATE's
167 // WHERE clause is true. Returns no rows when an existing row
168 // blocks us (completed, or in_progress but not yet stale), in
169 // which case we read the existing row to classify the outcome.
170 var owned int
171 err := s.pool.QueryRow(ctx,
172 `INSERT INTO idempotency_keys (
173 user_id, key, request_path, request_body_hash,
174 response_status, response_content_type, response_body,
175 status, created_at, completed_at
176 )
177 VALUES ($1, $2, $3, $4, 0, '', ''::bytea, 'in_progress', now(), NULL)
178 ON CONFLICT (user_id, key) DO UPDATE
179 SET request_path = EXCLUDED.request_path,
180 request_body_hash = EXCLUDED.request_body_hash,
181 response_status = 0,
182 response_content_type = '',
183 response_body = ''::bytea,
184 status = 'in_progress',
185 created_at = now(),
186 completed_at = NULL
187 WHERE idempotency_keys.status = 'in_progress'
188 AND idempotency_keys.created_at < now() - make_interval(secs => $5)
189 RETURNING 1`,
190 userID, key, path, bodyHash, staleSecs,
191 ).Scan(&owned)
192 if err == nil {
193 return ClaimResult{Outcome: OutcomeAcquired}, nil
194 }
195 if !errors.Is(err, pgx.ErrNoRows) {
196 return ClaimResult{}, err
197 }
198
199 // Lost the race. Read the existing row to classify.
200 var (
201 gotStatus string
202 gotHash string
203 gotCode int
204 gotCT string
205 gotBody []byte
206 )
207 err = s.pool.QueryRow(ctx,
208 `SELECT status, request_body_hash, response_status,
209 response_content_type, response_body
210 FROM idempotency_keys
211 WHERE user_id = $1 AND key = $2`,
212 userID, key,

Callers 1

Implementers 1

Storeinternal/identity/store.go

Calls 2

ScanMethod · 0.80
QueryRowMethod · 0.80

Tested by 1