Skip to content

allow docker specs on service restart - #1429

Merged
alexcos20 merged 1 commit into
next-4from
feature/allow_dockerspecs_on_service_restart
Jul 24, 2026
Merged

alexcos20 merged 1 commit into
next-4from
feature/allow_dockerspecs_on_service_restart

Conversation

@alexcos20

@alexcos20 alexcos20 commented Jul 23, 2026 •

Copy link
Copy Markdown
Member

Allow serviceRestart to change the Docker image / tag

Motivation

Service-on-Demand let a consumer start a long-running container from their own image, but
serviceRestart could only recreate the container on the exact same image. The realistic
recovery flow was impossible on-node:

Start a service on your own image → discover a bug → fix it → publish the corrected image
under a new tag → restart the service on the new tag.

Previously the only option was to stop the service and start a brand-new one, losing the paid
window, the reserved resources and the allocated host ports. This PR lets a restart carry a new
image spec while keeping payment, resources, duration and endpoints intact.

Behaviour — restart is now atomic (all-old or all-new)

A restart never mixes new request params over the stored job. There are exactly two modes,
chosen by whether the request carries any container param:

Request contains… Mode Container rebuilt from
none of image/tag/checksum/dockerfile/additionalDockerFiles/userData/dockerCmd/dockerEntrypoint REUSE the stored job, unchanged
any of the above (⇒ image becomes required) RESPEC the request only — omitted fields are empty, never inherited

Making image mandatory as soon as any container param is present is the discriminator that
makes a partial change impossible: you cannot ride a new userData/dockerCmd on top of the
stored image. In RESPEC mode the image spec is validated exactly like serviceStart (exactly one
of tag/checksum/dockerfile; dockerfile requires allowImageBuild on the environment).

Always preserved: identity (serviceId, owner, environment), payment/claimTx, resources,
duration/expiresAt, and the allocated host ports/endpoints. Only the container spec can change —
there is no extra charge, consistent with the pre-existing restart semantics.

This is not a breaking change: a restart with no container params behaves exactly as before.

Error responses

  • 400 — a container param was sent without image (a rejected partial change), or more than
    one of tag/checksum/dockerfile was supplied.
  • 403 — dockerfile supplied but the environment has allowImageBuild=false (fast-fail in the
    handler; the engine re-checks as the authoritative backstop).

Changes

Core

  • ServiceRestartCommand (src/@types/commands.ts) — added image, tag, checksum,
    dockerfile, additionalDockerFiles; documented the two-mode contract.
  • HTTP route (src/components/httpRoutes/compute.ts) — maps the new body fields.
  • ServiceRestartHandler (src/components/core/service/restartService.ts) — RESPEC validation
    (image required + mutual-exclusion) and the allowImageBuild fast-fail gate; forwards the full
    spec to the engine.
  • Engine (compute_engine_base.ts, compute_engine_docker.ts) — extended restartService /
    doRestartService signatures; doRestartService now computes the effective spec as a single
    atomic choice (RESPEC ⇒ request values + recomputed containerImage; REUSE ⇒ stored values),
    drives the pull-vs-build branch off the effective dockerfile, re-checks allowImageBuild, and
    persists the new image spec (image/tag/checksum/dockerfile/additionalDockerFiles/
    containerImage) onto the job so subsequent restarts and orphan-recovery see what is actually
    running. Vulnerability scanning of the new image is inherited from pullImageRef/
    buildImageFromSpec.

Tests

  • src/test/unit/service/serviceHandlers.test.ts — RESPEC forwarding, REUSE forwards-undefined,
    400 for partial changes (lone tag/userData/dockerCmd), 400 for multiple image modes, 403 for a
    build-disabled dockerfile respec, and 200 for a build-enabled one.
  • src/test/unit/compute.test.ts — engine-level: RESPEC applies + persists a new tag; RESPEC
    overrides cmd/entrypoint; REUSE reuses the whole stored spec; RESPEC clears cmd/entrypoint with
    empty arrays. (Adjusted the pre-existing tests to the new signature/semantics.)
  • src/test/integration/services.test.ts — (l4) restart on a freshly-published tag applies and
    persists the new image (endpoint still reachable, same hostPort + expiresAt); (l5) a container
    param without image is rejected 400.

Docs

  • docs/services.md, docs/API.md (request table + 400/403 responses), and the Postman
    collection updated for the two-mode contract and the bug-fix flow.

Summary by CodeRabbit

  • New Features

    • Service restarts now support applying a complete new container image specification.
    • Restarts can reuse the existing specification or rebuild from supplied image settings.
    • Updated image tags can redeploy services while preserving expiration times and host ports.
    • Dockerfile-based restarts are supported where image building is enabled.
  • Bug Fixes

    • Invalid or incomplete restart specifications are now rejected with clearer validation errors.
    • Restart updates consistently persist the newly applied container configuration.

@coderabbitai

coderabbitai Bot commented Jul 23, 2026 •

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 3e3fa0b8-fa44-4016-b034-8630af5a7452

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • ✅ Review completed - (🔄 Check again to review again)
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/allow_dockerspecs_on_service_restart

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.

@alexcos20 alexcos20 linked an issue Jul 23, 2026 that may be closed by this pull request
@alexcos20

Copy link
Copy Markdown
Member Author

/run-security-scan

@alexcos20 alexcos20 left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

AI automated code review (Gemini 3).

Overall risk: low

Summary:
This PR elegantly introduces RESPEC mode for serviceRestart, giving users the ability to dynamically update container specifications (e.g., swapping a new image tag to fix a bug) without losing their paid duration or host resources. The distinction between 'all-old' (REUSE) and 'all-new' (RESPEC) prevents fragmented, hard-to-debug container states. The logic is securely implemented with proper edge-case handling, including environment variable decryption validation and Dockerfile build checks.

Comments:
• [INFO][style] Good use of strict validation here. Enforcing an 'all-or-nothing' container specification when any single container parameter is supplied keeps the service state predictable and avoids messy, partial overwrites.
• [INFO][security] Excellent authoritative backstop. Even though the handler fast-fails, having the engine re-validate the daemon's allowImageBuild config prevents race conditions if the environment changes right before the engine processes the operation.
• [INFO][other] The tests clearly demonstrate the expected behavior of falling back to default image CMD and ENTRYPOINT when RESPEC mode omits the command overrides or supplies empty arrays. Very thorough testing.

@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)
src/components/core/service/restartService.ts (1)

95-186: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Unclaimed-payment restart returns 500, not the documented 400.

Every other invalid-restart condition (not found, expired, environment missing, services disabled, access denied, undecryptable userData) gets an explicit pre-check here that returns a 4xx via buildInvalidParametersResponse/inline status. "Payment never claimed" has no such pre-check — it is only detected inside engine.restartService (compute_engine_docker.ts, if (!job.payment?.claimTx) throw new Error(...)), and that thrown Error is caught by the generic catch at line 182 and mapped to httpStatus: 500.

This is reachable in production: processServiceStart's failure path can leave a job in Error status with payment.lockTx set but no claimTx (escrow lock failed outright) — that job is not Expired, so it sails past every existing guard and only fails deep inside the engine. docs/API.md documents this exact case as a 400 response, so clients built against the docs will mishandle it as a server error.

Add an explicit pre-check mirroring the Expired check above (and the dockerfile/allowImageBuild fast-fail pattern — handler fast-fails with the correct status, engine backstops):

🛡️ Proposed fix
     // State check — cannot restart an expired service
     if (job.status === ServiceStatusNumber.Expired)
       return buildInvalidParametersResponse(
         buildInvalidRequestMessage('Cannot restart an expired service')
       )
+
+    // Payment check — mirrors the engine's authoritative recheck, but must surface as a
+    // 400 (invalid request) rather than falling through to the generic 500 catch below.
+    if (!job.payment?.claimTx)
+      return buildInvalidParametersResponse(
+        buildInvalidRequestMessage(
+          'Cannot restart a service whose payment was never claimed (unpaid or refunded) — start a new service'
+        )
+      )

No test in serviceHandlers.test.ts/services.test.ts currently exercises this path — worth adding once fixed.

🤖 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 `@src/components/core/service/restartService.ts` around lines 95 - 186, Before
the existing Expired-state check in the restart handler, add a pre-check for
jobs with payment.lockTx set but no payment.claimTx, returning
buildInvalidParametersResponse with the documented 400 invalid-request response.
Keep engine.restartService as the authoritative backstop while ensuring this
condition no longer reaches the generic 500 catch; add coverage in the relevant
service handler tests if available.
🤖 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 `@src/components/core/service/restartService.ts`:
- Around line 95-186: Before the existing Expired-state check in the restart
handler, add a pre-check for jobs with payment.lockTx set but no
payment.claimTx, returning buildInvalidParametersResponse with the documented
400 invalid-request response. Keep engine.restartService as the authoritative
backstop while ensuring this condition no longer reaches the generic 500 catch;
add coverage in the relevant service handler tests if available.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 0cf50d9d-a435-46e5-90ad-5cc04317e811

📥 Commits

Reviewing files that changed from the base of the PR and between 85fa61b and 172076b.

📒 Files selected for processing (11)
  • docs/API.md
  • docs/Ocean Node.postman_collection.json
  • docs/services.md
  • src/@types/commands.ts
  • src/components/c2d/compute_engine_base.ts
  • src/components/c2d/compute_engine_docker.ts
  • src/components/core/service/restartService.ts
  • src/components/httpRoutes/compute.ts
  • src/test/integration/services.test.ts
  • src/test/unit/compute.test.ts
  • src/test/unit/service/serviceHandlers.test.ts

@alexcos20
alexcos20 merged commit c483ea1 into next-4 Jul 24, 2026
10 checks passed
@alexcos20
alexcos20 deleted the feature/allow_dockerspecs_on_service_restart branch July 24, 2026 04:37
alexcos20 added a commit that referenced this pull request Aug 28, 2026
* Shared Hardware Resource Pool for Compute Environments (#1390)

* shared hw resources

* Add Services (#1402)

* services

* bump contract to 2.9.0 (#1410)

* bump contract to 2.9.0

* cross-node auth tokens (#1404)

* cross-node auth tokens

* new validate auth token method

* stateless

* fix comment reviews

* revert to ask remote node

* finite number expiry + oom protection

* fix test

* remove meax ttl

* add peerid for signature check

* issuerpeerid on create auth token only

---------

Co-authored-by: alexcos20 <alex.coseru@gmail.com>

* Update src/components/Auth/index.ts

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

* Update src/components/Auth/index.ts

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

* fix network recreate (#1416)

* add cpuList (#1417)

* add cpuList

* services updates (#1422)

* Service lifecycle hardening

* remove axios (#1424)

* remove axios

* Feature/use native sqlite (#1423)

* use native sql

* resources constrains (#1425)

* resources constrains

* New updatedAt record for services (#1428)

* add updatedAt

* fix review comments

* lint

* allow docker specs on service restart (#1429)

* add more templates

* fix stable diffusion template

* fix extend service (#1435)

* new arg "release" for stop service (#1434)

* fix bugs

* fix comment

* add database retry

* add envs, validations, tests

* fix return type

* remove timeout

* fix review

* fix type

* Authenticate `PolicyServerPassthrough` / `initializePSVerification`, and stop logging credentials (#1449)

* Authenticate `PolicyServerPassthrough` / `initializePSVerification`, and stop logging credentials

* Feature/docker stats (#1436)

* docker stats

* remove serviceEndpoints (#1448)

* use custom ocean.js/cli

* fix merge errors

* Dependency and toolchain refresh (#1453)

* updates

* bump node version

* fix review

* use correct ocean.js branch

* workflows comfy (#1442)

* workflows comfy

* fix template

* fix download

* split in two bundles

* workflow id

* multiscene test

* multishoot v2

* fix v2

* v3 try

* voice concat

* update ugc product template to include new fields necessary on dashboard

* concat voices too

* install missing services

* cut to new scene

* remove sizeGb

* cleanup

* readd sizegb and schema

* minimax flow

* simplify

* minimax h3 v2

* v3 h3

* h3 v4

* image defaults

* speed improvement

* fixes

* fix box sizes

* fix corrupt model download

* new carachters

* fix tail sound

* add prompt creation model

* add minimax-music3 template

* ltx 2.5

* space out boxes ltx 2.5

* fix template id

* simplify flow

* fix bugs

* fix wrong img size

* fixes from official docs

* fix input out of range

* minimax h3 fix models

* fix new carachters

* minimax fixes

* find old videos

* fixes ltx 2.5

* try open github minimax flow

* live preview

* allinone fixes

* portarait mode

* more allinone fixes

* fix extend video

* fix libraries

* add muse, qwen38 templates

* fix openweb ui bootstrap

* remove pre configured admin

* fix muse tag

* ui flows

* add glm 5.2 template

* remove comment

* remove incorrect comment

* ecommerce flow fixes

* update templates to run with opencode

* adapt description

* text changes

* fixes ecom

* fixes for ecom

* fixes for ecom

* update glm5.2 template

* reduce context

* add glm5.2 template

* add deepseek harness

* update harness template

* update deepseek template

* update template

* update template

* use bucket snapshot

* deepseek fix

* remove hardcoded flows

* fix dockerfile and path

* update deepseek template

* add other type

* fix prettier

* update mamba version

* remove templates

* remove muse-glimmer

* remove files

* remove Agents.md

* fix coderabbit comments

---------

Co-authored-by: Denis <61563365+dnsi0@users.noreply.github.com>
Co-authored-by: alexcos20 <alex.coseru@gmail.com>

* Fix: indexer silently skipping DDOs on transient provider errors (#1458)

* fix indexer provider

* bump to node 24 (#1454)

* bump to node 24

* guard fix

* p2p_improve (#1455)

* add metrics (#1456)
* keep C2D running when the metadata DB is unreachable (#1457)

* guard ddo metadata

* fix ocean.js branch

* make  "Failed to advertise queued" and Caught "The operation was aborted" while republishing debug events, as they are not errors

* use proper ocean-cli branch

* add helper script

* fix ci

---------

Co-authored-by: Giurgiu Razvan <giurgiur99@gmail.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: Denis <61563365+dnsi0@users.noreply.github.com>
Co-authored-by: Bogdan Fazakas <bogdan.fazakas@gmail.com>
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.

ServiceRestart should allow to change docker image

1 participant