Skip to content

feat(task): scheduled pipeline deployments (deploy v2)#1073

Open
stepmikhaylov wants to merge 5 commits into
developfrom
feat/deploy-v2
Open

feat(task): scheduled pipeline deployments (deploy v2)#1073
stepmikhaylov wants to merge 5 commits into
developfrom
feat/deploy-v2

Conversation

@stepmikhaylov

@stepmikhaylov stepmikhaylov commented Jun 2, 2026

Copy link
Copy Markdown
Collaborator

Deploy v2 — scheduled pipeline deployments

Pipelines can now be deployed to the server and run autonomously on a schedule. A deployment persists a pipeline with a cron schedule (*/15 * * * *, @hourly, … or manual); the built-in scheduler fires due runs under the deploying user's account, with the same authentication, permission, and plan checks as an on-demand run.

Highlights

  • Full lifecycle API: rrext_deploy_add / update / list / status / remove.
  • Scheduler: loads persisted deployments on startup, never overlaps runs of the same deployment, tolerates bad records and transient store errors, drains in-flight runs on graceful shutdown.
  • Lost access (e.g. revoked API key) flips the deployment to errored and stops scheduling instead of retrying forever.
  • The credential stored for scheduled runs is never returned by the API or exposed in client types.

Clients ready to build on

The Python and TypeScript SDKs ship a complete, typed client.deploy namespace (add / remove / list / status / update) with integration tests and a docs page — fully capable for on-top development (SaaS UI and beyond).

Not the final version — remaining work

  • SaaS UI development, with iterative UI ↔ backend refinement and bug-fixing.
  • Deployment history.
  • Task run history.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Deployments can be scheduled and run persistently via the client deploy API; scheduled jobs are started/stopped reliably and removal unschedules them.
  • Bug Fixes

    • Scheduler more robust: rejects operations without credentials, marks errored deployments to avoid repeated failures, and better handles invalid schedules and runtime errors.
  • Documentation

    • New user guides and updated client docs with examples for deploy.add/remove/list/status/update.
  • Chores

    • Deployment record fields standardized to camelCase and client responses now omit sensitive tokens.

@coderabbitai

coderabbitai Bot commented Jun 2, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Refactors deployment records and storage, separates user credentials from client-visible payloads, introduces an in-process task execution facade, revises TaskScheduler API and lifecycle, wires scheduler into deploy commands and module startup/shutdown, and aligns Python/TypeScript clients and docs to camelCase deployment fields.

Changes

Deployment scheduling refactor with credential separation and client SDK alignment

Layer / File(s) Summary
Deployment record schema and client serialization
packages/ai/src/ai/account/models.py
DeploymentRecord replaces created_by with userId and userToken, renames timestamps to camelCase (createdAt/updatedAt), and introduces to_client_record() to serialize while excluding userToken.
Deployment store enumeration refactored
packages/ai/src/ai/account/deployment_store.py
iter_all() now yields DeploymentRecord objects only (not (client_id, record) tuples). Enumeration discovers users under users/ and lists deployments per user. Logging switches from debug to error for skipped records.
Task scheduler API and lifecycle refactoring
packages/ai/src/ai/modules/task/task_scheduler.py
schedule(record) drops client_id parameter. start() becomes synchronous and creates a background loop. New shutdown() replaces stop(). Task dataclass extended with schedule field. Dispatch refactored to spawn _start_task(...) concurrently and track in-flight starts. Startup loads all deployments with error logging.
In-process task execution facade
packages/ai/src/ai/modules/task/task_server_facade.py
New module adds start_server_task(server, token, pipeline) for in-process DAP execution without real sockets. Introduces ServerTaskAuthError for authentication failures. _InProcessTransport stores the last response in memory.
Deployment commands scheduler integration
packages/ai/src/ai/modules/task/commands/cmd_deploy.py
DeployCommands exposes _scheduler property. Add/update commands enforce userToken for scheduled runs, populate records with new fields, persist via deployments.save(), and call scheduler.schedule(record). Remove calls scheduler.unschedule(). List/status use to_client_record() for responses.
Task module scheduler initialization
packages/ai/src/ai/modules/task/__init__.py
Constructs TaskScheduler from task_server, registers on server.app.state.scheduler, starts it, and installs async shutdown hook that awaits both scheduler.shutdown() and task_server.shutdown().
Task server cleanup
packages/ai/src/ai/modules/task/task_server.py
Removes commented-out TaskScheduler TODO references from __init__, background tasks list, and shutdown sections.
Deployment store tests
packages/ai/tests/ai/account/test_deployment_store.py
make_record helper updated with userId parameter. test_save_and_get asserts userId. test_iter_all verifies pairs including CLIENT_2. New test validates userToken persists but to_client_record() omits it.
Task scheduler comprehensive test refactor
packages/ai/tests/ai/modules/task/test_task_scheduler.py
Refactored to use frozen-clock and mock start_server_task. New helpers: _run_loop_once, _drain, _patch_start_server_task. Load scenarios test startup enumeration. Dispatch scenarios validate token storage, auth failures, missing-token no-ops. Robustness tests cover deployment deletion and shutdown draining.
Client SDK alignment (Python and TypeScript)
packages/client-python/src/rocketride/deploy.py, packages/client-python/src/rocketride/types/deploy.py, packages/client-python/tests/test_deploy.py, packages/client-typescript/src/client/deploy.ts, packages/client-typescript/src/client/types/deploy.ts, packages/client-typescript/tests/deploy.test.ts, packages/client-typescript/docs/guide/methods/deploy.md
Deployment record fields renamed to camelCase (userId, createdAt, updatedAt). Docstrings updated to reference client methods instead of DAP commands. Tests assert userId presence, userToken absence, and camelCase fields. TypeScript guide fully documents the deploy namespace with methods, schedules, states, and error handling.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

Possibly related PRs

  • rocketride-org/rocketride-server#805: Refactors the already-added DeploymentStore/DeploymentRecord (iter_all yield type, userToken/camelCase serialization) and updates existing TaskScheduler/DeployCommands integration introduced in the deploy infrastructure scaffold.
  • rocketride-org/rocketride-server#600: Provides handle-based file-store APIs (fs_open/fs_read/fs_write/fs_close/fs_list_dir/fs_mkdir/fs_stat/fs_delete) that could be integrated with task storage and command operations.

Suggested reviewers

  • jmaionchi
  • Rod-Christensen

🐰 I patched the scheduler, tidied each token and id,
Records now hide secrets, clients see only the tid,
Tasks wake and dispatch through a gentle in-process door,
Tests hum like carrot choirs, docs sing camelCase once more.
Hop—merge with care, then let the deployments soar! 🚀

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 37.97% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat(task): scheduled pipeline deployments (deploy v2)' directly reflects the main objective of the PR: implementing scheduled pipeline deployments as Deploy v2.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/deploy-v2

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint install timed out. The project may have too many dependencies for the sandbox.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions github-actions Bot added module:client-python Python SDK and MCP client module:ai AI/ML modules module:client-typescript labels Jun 2, 2026
@github-actions

github-actions Bot commented Jun 2, 2026

Copy link
Copy Markdown

No description provided.

@stepmikhaylov stepmikhaylov force-pushed the feat/deploy-v2 branch 2 times, most recently from 3e25a2e to 44ebff6 Compare June 5, 2026 19:50
@stepmikhaylov stepmikhaylov force-pushed the feat/deploy-v2 branch 4 times, most recently from d08da2d to bf38cc3 Compare June 9, 2026 14:00
@stepmikhaylov stepmikhaylov force-pushed the feat/deploy-v2 branch 3 times, most recently from 3eefd52 to 96fe90d Compare June 10, 2026 14:21
@github-actions github-actions Bot added the docs Documentation label Jun 12, 2026
@stepmikhaylov stepmikhaylov changed the title feat/deploy v2 feat(task): scheduled pipeline deployments (deploy v2) Jun 12, 2026
@stepmikhaylov stepmikhaylov marked this pull request as ready for review June 12, 2026 15:06

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/ai/src/ai/modules/task/commands/cmd_deploy.py (1)

177-208: 🧹 Nitpick | 🔵 Trivial | 💤 Low value

Consider returning the updated record for consistency with add.

rrext_deploy_add returns record.to_client_record() while rrext_deploy_update returns an empty body. This inconsistency requires clients to make a follow-up status() call after update() to get the new updatedAt timestamp. If this is intentional (e.g., to avoid redundant serialization), consider documenting the API contract difference.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/ai/src/ai/modules/task/commands/cmd_deploy.py` around lines 177 -
208, The update handler on_rrext_deploy_update currently returns an empty body
while rrext_deploy_add returns record.to_client_record(); change
on_rrext_deploy_update to return the updated deployment in the response (e.g.,
build_response(request, body=record.to_client_record())) after save() and
scheduling so clients receive the new updatedAt and other client fields
consistently with rrext_deploy_add; ensure the record object provides
to_client_record() or serialize it the same way rrext_deploy_add does.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/ai/src/ai/modules/task/task_server_facade.py`:
- Around line 59-64: The current `exec_response` handling in the code that
awaits `conn.request('execute', arguments={'pipeline': pipeline})` only checks
top-level success and then indexes `exec_response['body']['token']`, which can
raise KeyError if `body` or `token` is missing; add defensive guards after the
success check to verify `exec_response.get('body')` is a dict and that
`exec_response['body'].get('token')` exists, and if not raise a clear
RuntimeError (e.g., "execute missing body" or "execute missing token") so
callers get a descriptive error instead of a KeyError.

In `@packages/client-python/src/rocketride/types/deploy.py`:
- Around line 35-49: Add or extend the Python SDK docs to document the deploy
API and the DeploymentRecord schema used by client.deploy.add,
client.deploy.list, and client.deploy.status: create a new documentation page
under packages/client-python/docs (e.g., deploy/deployment-record.md) or extend
index.md to include the DeploymentRecord fields and types, explicitly listing
pipeline: PipelineConfig, schedule: str, state:
Literal['active','paused','errored'], userId: str, createdAt: float, and
updatedAt: float, and ensure the public SDK signatures shown in the docs match
these exact field names.

---

Outside diff comments:
In `@packages/ai/src/ai/modules/task/commands/cmd_deploy.py`:
- Around line 177-208: The update handler on_rrext_deploy_update currently
returns an empty body while rrext_deploy_add returns record.to_client_record();
change on_rrext_deploy_update to return the updated deployment in the response
(e.g., build_response(request, body=record.to_client_record())) after save() and
scheduling so clients receive the new updatedAt and other client fields
consistently with rrext_deploy_add; ensure the record object provides
to_client_record() or serialize it the same way rrext_deploy_add does.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: f1b32a27-61ab-4808-858f-366db128eb3a

📥 Commits

Reviewing files that changed from the base of the PR and between b5b106b and 03c26ba.

📒 Files selected for processing (16)
  • packages/ai/src/ai/account/deployment_store.py
  • packages/ai/src/ai/account/models.py
  • packages/ai/src/ai/modules/task/__init__.py
  • packages/ai/src/ai/modules/task/commands/cmd_deploy.py
  • packages/ai/src/ai/modules/task/task_scheduler.py
  • packages/ai/src/ai/modules/task/task_server.py
  • packages/ai/src/ai/modules/task/task_server_facade.py
  • packages/ai/tests/ai/account/test_deployment_store.py
  • packages/ai/tests/ai/modules/task/test_task_scheduler.py
  • packages/client-python/src/rocketride/deploy.py
  • packages/client-python/src/rocketride/types/deploy.py
  • packages/client-python/tests/test_deploy.py
  • packages/client-typescript/docs/guide/methods/deploy.md
  • packages/client-typescript/src/client/deploy.ts
  • packages/client-typescript/src/client/types/deploy.ts
  • packages/client-typescript/tests/deploy.test.ts
💤 Files with no reviewable changes (1)
  • packages/ai/src/ai/modules/task/task_server.py

Comment thread packages/ai/src/ai/modules/task/task_server_facade.py
Comment thread packages/client-python/src/rocketride/types/deploy.py

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/client-python/docs/index.md (1)

24-30: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Align the Python methods table with the real SDK signature.

The table still uses JS-style options? and projectId, but the Python client exposes keyword-only args (schedule, pipeline) and project_id. That mismatch will mislead Python users and contradict the API shown below.

Proposed fix
-| `deploy.add(pipeline, options?)` | Persist a pipeline as a deployment and activate it |
-| `deploy.remove(projectId)` | Undeploy and delete the deployment |
+| `deploy.add(pipeline, *, schedule=None)` | Persist a pipeline as a deployment and activate it |
+| `deploy.remove(project_id)` | Undeploy and delete the deployment |
 | `deploy.list()` | List the authenticated user's deployments |
-| `deploy.status(projectId)` | Get one deployment record |
-| `deploy.update(projectId, options?)` | Replace the pipeline and/or schedule |
+| `deploy.status(project_id)` | Get one deployment record |
+| `deploy.update(project_id, *, pipeline=None, schedule=None)` | Replace the pipeline and/or schedule |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/client-python/docs/index.md` around lines 24 - 30, The methods table
in the Python docs is using JS-style signatures (e.g., options?, projectId)
which don't match the Python SDK; update the table to reflect the Python client
signatures (use keyword-only parameters like schedule and pipeline and
snake_case project_id) and ensure entries referencing RocketRideClient methods
match the actual Python function/method names and parameter styles (e.g.,
schedule, pipeline, project_id) so examples and parameter docs align with the
SDK.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@packages/client-python/docs/index.md`:
- Around line 24-30: The methods table in the Python docs is using JS-style
signatures (e.g., options?, projectId) which don't match the Python SDK; update
the table to reflect the Python client signatures (use keyword-only parameters
like schedule and pipeline and snake_case project_id) and ensure entries
referencing RocketRideClient methods match the actual Python function/method
names and parameter styles (e.g., schedule, pipeline, project_id) so examples
and parameter docs align with the SDK.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: e446cba2-90fe-485b-b0a5-bdaece78aac2

📥 Commits

Reviewing files that changed from the base of the PR and between 03c26ba and 10065ba.

📒 Files selected for processing (2)
  • packages/client-python/docs/index.md
  • packages/client-typescript/docs/guide/methods/deploy.md

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/client-python/tests/test_deploy.py (1)

101-112: 🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick win

Assert credential redaction on list() and status() too.

The leak-prevention check only covers add(), but the contract here is broader: stored deployment credentials must never come back from any deploy read path. Please add the same userToken-absence assertions for status() and for each record returned by list() in both SDK integration suites.

Based on the PR objective, the redaction guarantee applies to the full deploy lifecycle API, not just creation.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/client-python/tests/test_deploy.py` around lines 101 - 112, The test
currently asserts that add() does not echo stored credentials but misses the
same guarantees for other read paths; update the tests (starting from
test_add_returns_full_record) to call deploy.list() and iterate each returned
record asserting 'userToken' not in rec, and also call deploy.status(rec_id) for
a created record and assert 'userToken' not in that status response; apply the
same assertions in the other SDK integration test suites that exercise
deploy.list() and deploy.status() so all read paths (add, list, status) enforce
credential redaction.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/client-python/docs/index.md`:
- Line 258: The docs text about deployment States incorrectly implies that state
== 'active' always means cron ticks are firing; update the wording in
packages/client-python/docs/index.md to clarify that 'active' can also apply to
"manual" deployments (i.e., deployments with no schedule or schedule == 'manual'
that do not perform scheduled cron ticks) — reference the 'state' field and the
specific values 'manual', 'active', 'paused', and 'errored' and indicate that
manual deployments report state == 'active' but do not run scheduled ticks so
the default schedule may look like 'paused' even when state is 'active'.

---

Outside diff comments:
In `@packages/client-python/tests/test_deploy.py`:
- Around line 101-112: The test currently asserts that add() does not echo
stored credentials but misses the same guarantees for other read paths; update
the tests (starting from test_add_returns_full_record) to call deploy.list() and
iterate each returned record asserting 'userToken' not in rec, and also call
deploy.status(rec_id) for a created record and assert 'userToken' not in that
status response; apply the same assertions in the other SDK integration test
suites that exercise deploy.list() and deploy.status() so all read paths (add,
list, status) enforce credential redaction.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: cb3f0205-cf1b-44a1-8442-82554f1f8c44

📥 Commits

Reviewing files that changed from the base of the PR and between 10065ba and c04a449.

📒 Files selected for processing (14)
  • packages/ai/src/ai/modules/task/__init__.py
  • packages/ai/src/ai/modules/task/commands/cmd_deploy.py
  • packages/ai/src/ai/modules/task/task_scheduler.py
  • packages/ai/src/ai/modules/task/task_server.py
  • packages/ai/src/ai/modules/task/task_server_facade.py
  • packages/ai/tests/ai/modules/task/test_task_scheduler.py
  • packages/client-python/docs/index.md
  • packages/client-python/src/rocketride/deploy.py
  • packages/client-python/src/rocketride/types/deploy.py
  • packages/client-python/tests/test_deploy.py
  • packages/client-typescript/docs/guide/methods/deploy.md
  • packages/client-typescript/src/client/deploy.ts
  • packages/client-typescript/src/client/types/deploy.ts
  • packages/client-typescript/tests/deploy.test.ts
💤 Files with no reviewable changes (1)
  • packages/ai/src/ai/modules/task/task_server.py

Comment thread packages/client-python/docs/index.md
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

docs Documentation module:ai AI/ML modules module:client-python Python SDK and MCP client module:client-typescript

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant