Skip to content

fix: claim the message id before creating the message - #47

Merged
babs merged 2 commits into
masterfrom
fix/claim-message-id-before-create
Sep 11, 2026
Merged

babs merged 2 commits into
masterfrom
fix/claim-message-id-before-create

Conversation

@babs

@babs babs commented Sep 11, 2026

Copy link
Copy Markdown
Member

Fixes the orphaned Teams card: a merge request was closed, its notification updated, and the card stayed up forever with nothing pointing at it.

activity-api answered 201 seventeen seconds after the create call. The client had given up at ten, so the returned id was never stored. The message existed in Teams, the ref carried message_id = NULL, and at close the deletion scheduler skipped it and dropped the ref.

Change

  • The id is generated and written to merge_request_message_ref before the create call, then sent in the payload. A lost answer no longer loses the handle.
  • A create refused outright (400/409, both answered before anything reaches Teams) gives the id back. So does any patch activity-api answers with invalid message_id. Without that, a ref would stay locked onto an id nothing can resolve and the merge request would never get a card at all.
  • The concurrent-create race is settled by the claim itself: the loser never posts. The compensating remote DELETE is gone, about 40 lines removed.
  • A ref reaching deletion without a message_id is now logged as a possible orphan instead of being dropped silently.
  • periodic_cleanup treats activity-api's invalid message_id as terminal, so an id claimed but never delivered cannot loop forever in msg_to_delete.
  • ACTIVITY_API_TIMEOUT_SECONDS and GITLAB_API_TIMEOUT_SECONDS replace five hard-coded values, same defaults.

Deploy order

Requires activity-api >= 0.12.0, which adds the caller-chosen message_id field. Deploy it first. Against an older activity-api the field is silently ignored (pydantic extra='ignore') and behaviour falls back to what it is today, so nothing breaks, but the bug is not fixed until both are up.

256 tests, 84% coverage. Every new guard was checked red against the code without the fix.

activity-api answered 201 seventeen seconds after a create call whose client
had given up at ten, so the id never reached the database. At close the ref
carried no message_id, no deletion was scheduled, and the card stayed in Teams
with nothing left pointing at it.

The id is now generated and stored before the call, so a lost answer costs
nothing. A create refused outright with 400 or 409 gives the id back, and so
does any patch activity-api answers with `invalid message_id`: without that,
a ref would be stuck patching a ghost and the merge request would never get a
card at all. Claiming first also settles the concurrent-create race with no
compensating delete, since the loser never posts.

ACTIVITY_API_TIMEOUT_SECONDS and GITLAB_API_TIMEOUT_SECONDS replace the
hard-coded timeouts, same defaults.
starlette 1.x makes its TestClient import httpx2 and raises on the httpx
fallback, so collection of the integration tests fails on a fresh install.
@babs
babs merged commit c1f2851 into master Sep 11, 2026
1 check passed
@babs
babs deleted the fix/claim-message-id-before-create branch September 11, 2026 12:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant