Skip to content

Refactor/single process multiple services#785

Open
renatomaia wants to merge 14 commits into
next/2.0from
refactor/SingleProcessMultipleServices
Open

Refactor/single process multiple services#785
renatomaia wants to merge 14 commits into
next/2.0from
refactor/SingleProcessMultipleServices

Conversation

@renatomaia

@renatomaia renatomaia commented Jun 23, 2026

Copy link
Copy Markdown
  • Introduce a new single-process service runtime:

    • Add Supervisor to create, run, stop, and tear down multiple services under one process.
    • Services are created through factory functions that validate configuration and initialize service instances.
    • SIGINT and SIGTERM are handled by the supervisor and translated into graceful shutdown. Unused SIGHUP reload support was removed.
    • Child-service startup failures, unexpected exits, and shutdown errors are logged and propagated through the supervisor.
    • Multiple errors are now returned as a single error using errors.Join.
  • Simplify the service lifecycle protocol:

    • Service shutdown is now driven by context.Context cancellation.
    • The previous service.stopping / IsStopping state and per-service Stop signaling were removed.
    • Services that need to stop internal work, HTTP servers, tickers, or background loops must watch the provided context.
    • Reload was removed because it was unused.
    • Alive is no longer implemented per service. /livez is now supervisor-owned: it is true while the supervisor is serving and not stopping.
    • Teardown was added so services can release resources after Serve exits, although it is not currently being used.
  • Add reusable service templates:

    • TickServiceTemplate for tick-based services:
      • Advancer
      • Claimer
      • EVM Reader
      • PRT
      • Validator
    • HTTPServiceTemplate for HTTP-backed services:
      • JSON-RPC
      • Inspector
      • Telemetry
  • Refactor supervised services:

    • Inspector and JSON-RPC are now first-class supervised HTTP services.
    • Inspector now uses the shared HTTP hardening and startup/shutdown path.
    • Telemetry is now a built-in supervisor-managed HTTP service.
    • The machine manager is created as a shared component before service startup and closed after services terminate, instead of being owned by Advancer teardown.
  • Update tick and context APIs:

    • Functions that need a context now receive it as an argument instead of reading it from service state.
    • Tick-based services now return (bool, error) from Tick; the boolean controls whether another immediate tick should be scheduled.
    • Service APIs now return joined error values instead of []error.
  • Behavior changes to note:

    • Supervisor shutdown is consistently triggered by context cancellation, OS signals, service initialization failure, or unexpected child-service exit.
    • Listener failures and unexpected exits from Inspector or JSON-RPC now participate in supervisor shutdown like
      other service failures.

@renatomaia
renatomaia requested review from mpolitzer and vfusco June 23, 2026 12:58
@renatomaia renatomaia self-assigned this Jun 23, 2026
@renatomaia
renatomaia force-pushed the refactor/SingleProcessMultipleServices branch 3 times, most recently from 758ef1a to 426dd48 Compare June 26, 2026 13:53
@renatomaia
renatomaia marked this pull request as draft July 8, 2026 18:08
@renatomaia
renatomaia force-pushed the refactor/SingleProcessMultipleServices branch 2 times, most recently from 7902169 to 988508b Compare July 15, 2026 20:03
@renatomaia
renatomaia marked this pull request as ready for review July 15, 2026 20:16
@renatomaia
renatomaia force-pushed the refactor/SingleProcessMultipleServices branch from 988508b to 40a197a Compare July 16, 2026 13:10
mpolitzer
mpolitzer previously approved these changes Jul 16, 2026

Copilot AI 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.

Pull request overview

This PR refactors the runtime from a “one service owns others” model into a single-process supervisor that creates and manages multiple services (tick-based and HTTP-based) under one lifecycle, driven primarily by context.Context cancellation and errors.Join error aggregation.

Changes:

  • Introduces a Supervisor runtime to create, start, stop, and tear down multiple services in one process (including OS signal handling and supervisor-owned /livez).
  • Adds reusable service templates: TickServiceTemplate (polling + immediate retick via (bool, error)) and HTTPServiceTemplate (hardened HTTP server + middleware wiring + graceful shutdown).
  • Refactors core services (advancer, claimer, evmreader, prt, validator, inspect, jsonrpc) and CLIs to use the new templates/supervisor and to pass context explicitly into work functions.

Reviewed changes

Copilot reviewed 68 out of 68 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
test/validator/validator_test.go Updates validator integration tests to new Create and Tick(ctx) APIs.
pkg/service/tick.go Adds tick-based service template with reschedule-by-return-value semantics.
pkg/service/tick_test.go Adds tests for TickServiceTemplate.Serve() behavior (cancellation, reschedule).
pkg/service/telemetry.go Adds supervisor-owned telemetry HTTP service exposing /readyz and /livez.
pkg/service/telemetry_test.go Updates telemetry tests for supervisor-managed telemetry service.
pkg/service/supervisor.go Adds Supervisor orchestration (init/start/stop/teardown, signals, telemetry).
pkg/service/supervisor_test.go Adds coverage for supervisor lifecycle, readiness, failure modes, stop semantics.
pkg/service/service_test.go Replaces legacy service loop tests with a basic BaseTemplate invariant test.
pkg/service/http_service.go Adds reusable hardened HTTP service template with graceful shutdown on ctx cancel.
internal/validator/validator.go Refactors validator to TickServiceTemplate and Tick(ctx) (bool, error).
internal/validator/validator_test.go Updates validator unit tests to new base template init.
internal/prt/validation_test.go Updates PRT validation tests to avoid relying on service-owned context/cancel.
internal/prt/service.go Refactors PRT to TickServiceTemplate, explicit context usage, internal eth client creation.
internal/prt/fixture_test.go Updates PRT fixtures to use TickServiceTemplate embedding/init.
internal/node/node.go Removes legacy node “parent service with children” implementation.
internal/manager/types.go Removes Close() error from MachineProvider interface.
internal/manager/manager.go Changes machine manager Close() to log errors instead of returning joined error.
internal/manager/manager_test.go Updates tests to validate close failures via logs rather than returned error.
internal/jsonrpc/util_test.go Updates JSON-RPC test helper to new Create signature and config pattern.
internal/jsonrpc/service.go Refactors JSON-RPC into HTTPServiceTemplate-based supervised service.
internal/jsonrpc/service_test.go Updates JSON-RPC tests to use HTTPServiceTemplate fields (Server, Admission).
internal/inspect/inspect.go Refactors inspector into HTTPServiceTemplate-based supervised service.
internal/inspect/inspect_test.go Updates inspect tests to initialize base template for logging/fields.
internal/evmreader/service.go Refactors evmreader into TickServiceTemplate, supports injected eth client.
internal/evmreader/service_config_test.go Updates evmreader config tests for new create/init and teardown behavior.
internal/evmreader/sealedepochs_test.go Updates sealed epochs tests to init base template rather than legacy service create.
internal/evmreader/output_test.go Updates output tests to call Serve(ctx) and new tick template init.
internal/evmreader/input_test.go Updates input tests to call Serve(ctx) under new template.
internal/evmreader/input_scan_units_test.go Updates scan unit tests to embed/init tick template logger.
internal/evmreader/foreclosure_test.go Updates foreclosure fixture to init tick template instead of legacy service.
internal/evmreader/evmreader.go Updates evmreader Tick(ctx) signature and context usage.
internal/evmreader/evmreader_test.go Refactors tests to run evmreader under supervisor and updated readiness semantics.
internal/evmreader/edge_cases_test.go Updates edge-case tests to stop supervisor instead of canceling service context.
internal/evmreader/accounts_drive_proved_test.go Updates fixture to init tick template instead of legacy service create.
internal/cli/cobra.go Suppresses logging for context.Canceled while preserving cobra.CheckErr.
internal/claimer/submit.go Threads context through claim submission pipeline; joins errors instead of []error.
internal/claimer/stage.go Threads context; returns joined error rather than slice; updates staging flow.
internal/claimer/stage_test.go Updates staging tests for new signatures and context plumbing.
internal/claimer/service.go Refactors claimer into TickServiceTemplate; creates eth client if not injected.
internal/claimer/service_test.go Updates claimer create tests for new config-driven polling interval and type assertions.
internal/claimer/reverts.go Threads context into revert classification/state mutation paths.
internal/claimer/reverts_test.go Updates revert tests for new function signatures (ctx) and joined error semantics.
internal/claimer/inflight.go Threads context through in-flight tx polling and state updates.
internal/claimer/inflight_test.go Updates in-flight tests for new signatures and joined errors.
internal/claimer/foreclosure.go Threads context; joins errors in foreclosure processing.
internal/claimer/foreclosed_apps_test.go Updates tests for context-param foreclosure functions and joined error unwrapping.
internal/claimer/fixtures_test.go Updates fixtures to init tick template instead of legacy service context fields.
internal/claimer/divergence.go Threads context into divergence/error paths and DB mutations.
internal/claimer/divergence_test.go Updates divergence tests to pass context and assert joined error behavior.
internal/claimer/claimer.go Refactors main Tick pipeline to Tick(ctx) (bool, error) + reschedule by return value.
internal/claimer/claimer_test.go Updates tick test to assert reschedule boolean instead of reschedule channel draining.
internal/claimer/claim_status.go Threads context into claim status reconciliation DB updates.
internal/claimer/claim_status_test.go Updates claim status tests for new ctx signatures.
internal/claimer/accept.go Threads context through accept pipeline; joins errors instead of slices.
internal/advancer/service.go Refactors advancer to tick template, uses supervisor for coordinated shutdown.
internal/advancer/advancer.go Removes reliance on IsStopping; triggers global shutdown via supervisor on fatal errors.
internal/advancer/advancer_test.go Updates advancer tests for new Tick(ctx) signature and supervisor stop semantics.
cmd/cartesi-rollups-validator/root/root.go Switches validator binary to supervisor-managed startup/runtime.
cmd/cartesi-rollups-prt/root/root.go Switches PRT binary to supervisor-managed startup/runtime.
cmd/cartesi-rollups-node/root/root.go Replaces legacy node service with supervisor factories + shared machine manager.
cmd/cartesi-rollups-jsonrpc-api/root/root.go Switches JSON-RPC binary to supervisor-managed startup/runtime.
cmd/cartesi-rollups-evm-reader/root/root.go Switches evm-reader binary to supervisor-managed startup/runtime.
cmd/cartesi-rollups-claimer/root/root.go Switches claimer binary to supervisor-managed startup/runtime.
cmd/cartesi-rollups-advancer/root/root.go Switches advancer binary to supervisor-managed startup/runtime (and optional inspect).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread pkg/service/tick.go
Comment thread pkg/service/supervisor.go
Comment thread pkg/service/supervisor.go
@renatomaia
renatomaia force-pushed the refactor/SingleProcessMultipleServices branch from 40a197a to b144052 Compare July 16, 2026 18:14
@renatomaia
renatomaia force-pushed the refactor/SingleProcessMultipleServices branch from b144052 to 83fe452 Compare July 17, 2026 18:24
@vfusco
vfusco requested a review from Copilot July 24, 2026 11:13

Copilot AI 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.

Pull request overview

Copilot reviewed 69 out of 69 changed files in this pull request and generated 6 comments.

Comments suppressed due to low confidence (1)

pkg/service/supervisor.go:216

  • Serve() writes to the shared local variable err from multiple subservice goroutines (err = ErrServiceStopped) without synchronization. If more than one subservice exits unexpectedly around the same time, this is a data race under the Go race detector and the final returned error is nondeterministic. Consider using an atomic flag (since the only value is ErrServiceStopped), or sending unexpected-exit signals on a channel and aggregating in the main goroutine after waiting for all services.

Comment thread pkg/service/supervisor.go
Comment on lines +121 to +143
func (s *Supervisor) Serve(ctx context.Context) error {
// CAS achieves once-semantics: the second caller returns immediately
// (fire-and-forget) rather than blocking like sync.Once. This is safe
// because the orchestrator calls Cancel() after Stop() and waits for
// the Serve goroutine to exit.
if !s.serving.CompareAndSwap(false, true) {
return ErrAlreadyStarted
}

defer func() {
s.Stop(false) // make sure a stop is requested (e.g. when exited due to no services)
close(s.stoppedCh)
s.context, s.cancel = context.WithCancel(context.Background())
s.stopping.Store(false) // let another stop to be scheduled
s.serving.Store(false) // let another serve to be initiated
}()

// check if we were stopped already.
if s.stopping.Load() {
return nil
}

s.Logger.Info("Supervisor initiated")
Comment thread pkg/service/supervisor.go
Comment on lines +242 to +252
func (s *Supervisor) Stop(wait bool) bool {
stopped := s.stopping.CompareAndSwap(false, true)
if stopped {
s.Logger.Info("Stopping supervisor")
s.stoppedCh = make(chan struct{})
s.cancel()
}

if wait {
<-s.stoppedCh
}
Comment on lines +89 to +92
// Serve opens the HTTP listener and runs the server. Returns nil on
// graceful shutdown.
func (s *HTTPServiceTemplate) Serve(ctx context.Context) error {
listener, err := s.Listen("tcp", s.Server.Addr)
Comment thread pkg/service/tick_test.go
Comment on lines +111 to +113
// When SignalReschedule() is called from Tick(), Serve() should call
// Tick() again immediately without waiting for the timer.
impl.onTick = func(n int32) bool {
"sync/atomic"
"testing"
"time"
func (s *ServeSuite) TestServeExitsAfterStopIsCompleteOnSupervisorShutdown() {
Comment on lines +50 to 53
s := &Service{
supervisor: c.Supervisor,
snapshotsDir: c.Config.SnapshotsDir,
}
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.

3 participants