Skip to content

Standardize durable platform jobs and make app publishing async - #533

Open
jackmusick wants to merge 2 commits into
mainfrom
532-standardize-platform-jobs
Open

Standardize durable platform jobs and make app publishing async#533
jackmusick wants to merge 2 commits into
mainfrom
532-standardize-platform-jobs

Conversation

@jackmusick

Copy link
Copy Markdown
Collaborator

Summary

Introduces the first reusable durable platform-job kernel and migrates application publishing onto it, fixing the production failure mode where the initiating HTTP request timed out while publish continued invisibly.

  • persists generic jobs, leases, attempts, progress, results, errors, cancellation state, and dedupe keys in PostgreSQL
  • claims work from the existing scheduler container and runs each job in a fresh child process inside the scheduler cgroup, with lease fencing, heartbeat recovery, timeouts, memory admission/hard-pressure handling, and process-group termination
  • changes app publish to 202 PlatformJobAccepted, rebuilds current source before promotion, promotes only manifest-declared bundle outputs with bounded concurrency, and writes the live manifest last
  • adds bifrost apps publish <ref> with short-request polling and clear terminal errors; generic bifrost api now explains that a timed-out request may still be processing
  • sends the exact PlatformJobPublic contract over the existing notification WebSocket and projects progress into the existing Notification Center; the UI does not poll
  • converts MCP app publish to a thin REST wrapper so REST/CLI/UI/MCP share the same build guard and publish semantics
  • preserves same-requester idempotent reuse; concurrent requests from a different authorized user receive 409 instead of an inaccessible/misleading job ID

Compatibility

This is intentionally a breaking REST/CLI contract change. POST /api/applications/{id}/publish changes from synchronous 200 ApplicationPublic to asynchronous 202 PlatformJobAccepted, followed by GET /api/platform-jobs/{id}.

CONTRACT_VERSION is bumped from 7 to 8 in both the server and baked CLI. That hard contract gate is the repository's current effective minimum-CLI-version mechanism; the older semver min_cli_version field was retired because prerelease/build rollout ordering made it unsafe.

No new container is introduced. Platform jobs run from the existing scheduler pod/container; workflow and agent executions remain on the existing worker path. Existing specialized job implementations (Solution deploy/export, reindexing, etc.) are deliberately unchanged in PR 1 and can migrate incrementally onto this kernel in follow-up PRs.

Verification

  • backend unit: 5,416 passed, 3 skipped
  • backend E2E, split into fresh-token partitions: 1,649 passed, 54 skipped
  • focused cross-requester publish conflict: passed
  • client unit: 1,662 passed across 229 files
  • Playwright: 107 passed, 2 skipped, including publish completion through WebSocket notifications
  • Pyright: 0 errors/warnings
  • Ruff: passed
  • TypeScript: passed
  • ESLint: 0 errors (one pre-existing React Hook Form compiler warning)
  • generated OpenAPI/CLI skill mirrors and git diff --check: passed

The monolithic backend all run was not used as the final evidence because its session token expired during the long Solution segment while the API and scheduler remained healthy. All backend coverage was then rerun successfully in fresh-token partitions.

No production deployment or production data mutation was performed.

Refs #532

publish_platform_job_update,
)

logger = logging.getLogger(__name__)
except TimeoutError:
try:
os.killpg(process.pid, signal.SIGKILL)
except ProcessLookupError:
timeout=HEARTBEAT_INTERVAL_SECONDS,
)
break
except TimeoutError:
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.

2 participants