Skip to content

fix(apple): ignore push teardown failures after a reopen - #2055

Merged
abnegate merged 2 commits into
mainfrom
fix/apple-push-log-interleave
Oct 15, 2026
Merged

abnegate merged 2 commits into
mainfrom
fix/apple-push-log-interleave

Conversation

@abnegate

Copy link
Copy Markdown
Member

What

Push.inBackground stops reporting a fire-and-forget broker call's failure once the close() that caused it has happened, even if a later subscribe() has since reopened the connection and cleared closing.

Why

When the last subscription is dropped, unsubscribe starts a background UNSUBSCRIBE and then calls close(). The disconnect fails that in-flight UNSUBSCRIBE with MQTTError.serverClosedConnection. inBackground suppressed the failure only while the global closing flag was set. A subscribe() that reopens before the failure arrives resets closing = false. The teardown failure then surfaced as an error: to onError, or to stderr when none is registered.

That stderr line is behind the intermittent Tests / AppleSwift61 failures. SwiftPM delivers the test's stdout and stderr on one stream, and stdout is block-buffered, so the line Appwrite Push: serverClosedConnection gets spliced into the middle of an earlier stdout line. Every expected line after it shifts. It was seen on #1955 (inside the Operator helper output) and #1817 (inside the query-transport output).

The fix records closeGeneration when the background call starts and skips reporting if it has changed. This is the same check subscribe() already uses to detect an intervening close().

Tests

The "Push close from callback" e2e step now reopens from inside the callback that dropped the last subscription, which is the racing order. It also registers onError, so a leaked teardown failure fails that one line (error: …) instead of corrupting the output stream.

The test commit is pushed on its own first, so CI can show it failing without the fix. The fix follows in the next commit.

Not verified

  • I couldn't run the Apple e2e locally because the local Docker daemon was unresponsive. The SDK generated from the e2e fixture, plus the updated Tests.swift, does compile with swift build --build-tests.
  • The race is timing-dependent, so the test-only run may happen to pass.
  • The swift-format check of the generated Push.swift used a local config with one extra key (orderedImports.shouldGroupImports), because the local swift-format is newer than 6.3. It passes lint --strict.

🤖 Generated with Claude Code

Reopening at once from the callback that dropped the last subscription
races the closed connection's in-flight UNSUBSCRIBE. Collect onError so
a teardown failure that leaks out fails this line instead of landing on
stderr, where it splices into the buffered stdout the suite compares.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@hansi-codes

hansi-codes Bot commented Oct 15, 2026 •

Copy link
Copy Markdown

🟢 Tier S · Ready to merge

The generation is captured before the background task starts and checked when it fails, correctly identifying operations that crossed a deliberate close.

The Apple push SDK now tags fire-and-forget broker operations with the close generation at launch and suppresses failures from operations that cross a deliberate close, even if a later subscription reopens the connection. The Apple e2e callback teardown scenario reopens after unsubscribing the final topic and checks that no teardown error is reported.

Latest changes: The newest commits add the close-generation check to inBackground, preventing a teardown failure from surfacing after subscribe() clears closing.

Verdict New comments Fixed Still open
✅ Approved 0 0 0
📂 Walkthrough · 2
File Change
templates/apple/Sources/Services/Push.swift.twig Suppresses background-operation errors when a deliberate close occurs after the operation starts.
tests/e2e/languages/apple/Tests.swift Reopens from the last-unsubscribe callback and checks that teardown errors are not reported.

Reviewed the commits since 88514a5 · Details · Comment @hansi-codes review to re-run, or mention @hansi-codes with a question.

hansi-codes[bot]
hansi-codes Bot previously requested changes Oct 15, 2026

@hansi-codes hansi-codes Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Tier B · 1 blocking finding to address. Summary

Comment thread tests/e2e/languages/apple/Tests.swift
Dropping the last subscription starts a background UNSUBSCRIBE and then
closes, so the UNSUBSCRIBE fails with serverClosedConnection. A
subscribe() that reopens first clears 'closing', and the teardown
failure then reached onError or stderr. Skip reporting when a close()
has happened since the call started, as subscribe() already does.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@hansi-codes
hansi-codes Bot dismissed their stale review October 15, 2026 05:27

The findings that requested changes are resolved. See the summary comment for what is still open.

@hansi-codes hansi-codes Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Tier S · Looks good to merge. Summary

@abnegate
abnegate merged commit d95ea6c into main Oct 15, 2026
96 of 101 checks passed
@abnegate
abnegate deleted the fix/apple-push-log-interleave branch October 15, 2026 06:13
@abnegate abnegate mentioned this pull request Oct 15, 2026
5 tasks done
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