anthropics / anthropics/anthropic-sdk-python

environments work poller: ack-before-yield makes any consumer failure permanently strand the work item — request deferred ack or a nack/fail API

Offen
#1,746 0 Kommentare 0 Reaktionen 0 zugewiesene Personen Auf GitHub ansehen
Vorherrschende Sprache
Python
Sterne
3.9k
Forks
853
Ø Merge
1 T. 18 Std.
Gemergte PRs (30 T.)
11

Beschreibung

`anthropic.lib.environments._poller` acknowledges every work item **before** yielding it to the consumer (`_poller.py:234`; docstring at `:66`: "Each yielded `BetaSelfHostedWork` has already been ack'd"). There is no deferred-ack option and no nack/fail API. Verified identical from 0.109.1 through 0.116.0.

For self-hosted managed-agents environments this makes any consumer-side exception after the yield permanently strand that session:

- the acked item freezes in `state='starting'` with `latest_heartbeat_at=null`;
- `reclaim_older_than_ms` cannot reach it (it only reaches unacknowledged items), and lease-TTL re-queue never fires (requires a first heartbeat);
- the platform keeps one work item per session, so all subsequent `user.message` events park in `requires_action` with **no new work enqueued** — the session is wedged until an operator runs `work.stop(work_id, force=True)` and sends a `user.interrupt`.

We hit this in production twice in one day (different consumer exceptions, same terminal state) and separately counted 29 items stuck in `starting` with null heartbeats.

## Ask

Either of:
1. **Deferred ack**: an opt-in poller mode that acks after the consumer callback returns successfully (at-least-once semantics), or
2. **nack/fail API**: a way for a consumer to return a failed item to a re-pendable state.

Related, happy to file separately: documenting which work-item states re-enqueue on which user events (empirically: `stopped` re-pends on message/interrupt; a dead-heartbeat `started` item only after a server-side stop ~5 min later; an acked-but-never-heartbeated `starting` item never), and a server-side janitor for `starting` + null-heartbeat items older than a TTL.

## Workaround we ship today

Consumer retry + `work.stop(force=True)` on final failure, plus a scheduled sweep that force-stops stale `starting` items and interrupts sessions parked in `requires_action` with no live worker. Effective, but every self-hosted-environment consumer will independently rediscover this failure class — ack-after-success semantics in the SDK would eliminate it.

Beitragsleitfaden

Beitragsleitfaden öffnen

Bewertung

Dieses Issue wurde noch nicht bewertet.

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.