From 137d5aa8fdc18fe67958f1aa893e1be36f03a306 Mon Sep 17 00:00:00 2001 From: Valery Piashchynski Date: Tue, 12 May 2026 17:10:25 +0200 Subject: [PATCH 1/4] feat: add Connect-RPC service definitions for informer, metrics, resetter, tcp Tier C plugin RPC migration: each gets its own v1 service block, with read-only methods marked NO_SIDE_EFFECTS so generated Connect handlers accept HTTP GET. informer/v1.InformerService - ListPlugins, GetWorkers, GetJobs (GET) - AddWorker, RemoveWorker metrics/v1.MetricsService - Add, Sub, Observe, Set (mutate prometheus state) - Declare, Unregister - CollectorType enum + Objective repeated message (proto3 disallows float-keyed maps) resetter/v1.ResetterService - ListPlugins (GET) - Reset tcp/v1.TCPService - Close --- roadrunner/api/informer/v1/service.proto | 80 ++++++++++++++++++++++++ roadrunner/api/metrics/v1/service.proto | 80 ++++++++++++++++++++++++ roadrunner/api/resetter/v1/service.proto | 30 +++++++++ roadrunner/api/tcp/v1/service.proto | 21 +++++++ 4 files changed, 211 insertions(+) create mode 100644 roadrunner/api/informer/v1/service.proto create mode 100644 roadrunner/api/metrics/v1/service.proto create mode 100644 roadrunner/api/resetter/v1/service.proto create mode 100644 roadrunner/api/tcp/v1/service.proto diff --git a/roadrunner/api/informer/v1/service.proto b/roadrunner/api/informer/v1/service.proto new file mode 100644 index 0000000..f008d30 --- /dev/null +++ b/roadrunner/api/informer/v1/service.proto @@ -0,0 +1,80 @@ +syntax = "proto3"; + +package informer.v1; + +option go_package = "github.com/roadrunner-server/api-go/v6/informer/v1;informerV1"; +option php_metadata_namespace = "RoadRunner\\Informer\\DTO\\V1\\GPBMetadata"; +option php_namespace = "RoadRunner\\Informer\\DTO\\V1"; + +// ProcessState mirrors github.com/roadrunner-server/pool/v2/state/process.State — +// one entry per OS-level worker process managed by a plugin. +message ProcessState { + int64 pid = 1; + int64 status = 2; + uint64 num_execs = 3; + int64 created = 4; + uint64 memory_usage = 5; + double cpu_percent = 6; + string command = 7; + string status_str = 8; +} + +// JobState mirrors github.com/roadrunner-server/api-plugins/v6/jobs.State — +// one entry per consumer pipeline registered with the jobs plugin. +message JobState { + string pipeline = 1; + string driver = 2; + string queue = 3; + int64 active = 4; + int64 delayed = 5; + int64 reserved = 6; + bool ready = 7; + uint64 priority = 8; + string error_message = 9; +} + +message ListPluginsRequest {} +message PluginsList { + repeated string plugins = 1; +} + +message GetWorkersRequest { + string plugin = 1; +} +message WorkersList { + repeated ProcessState workers = 1; +} + +message GetJobsRequest { + string plugin = 1; +} +message JobsList { + repeated JobState states = 1; +} + +message AddWorkerRequest { + string plugin = 1; +} +message RemoveWorkerRequest { + string plugin = 1; +} + +message Response { + bool ok = 1; +} + +// InformerService exposes introspection RPCs for plugins that manage workers +// (jobs, service, kv, etc.) and lets callers add or remove workers at runtime. +service InformerService { + rpc ListPlugins(ListPluginsRequest) returns (PluginsList) { + option idempotency_level = NO_SIDE_EFFECTS; + } + rpc GetWorkers(GetWorkersRequest) returns (WorkersList) { + option idempotency_level = NO_SIDE_EFFECTS; + } + rpc GetJobs(GetJobsRequest) returns (JobsList) { + option idempotency_level = NO_SIDE_EFFECTS; + } + rpc AddWorker(AddWorkerRequest) returns (Response); + rpc RemoveWorker(RemoveWorkerRequest) returns (Response); +} diff --git a/roadrunner/api/metrics/v1/service.proto b/roadrunner/api/metrics/v1/service.proto new file mode 100644 index 0000000..413be87 --- /dev/null +++ b/roadrunner/api/metrics/v1/service.proto @@ -0,0 +1,80 @@ +syntax = "proto3"; + +package metrics.v1; + +option go_package = "github.com/roadrunner-server/api-go/v6/metrics/v1;metricsV1"; +option php_metadata_namespace = "RoadRunner\\Metrics\\DTO\\V1\\GPBMetadata"; +option php_namespace = "RoadRunner\\Metrics\\DTO\\V1"; + +// CollectorType enumerates the supported Prometheus collector kinds. The +// numeric values are stable; do not reuse or renumber. +enum CollectorType { + COLLECTOR_TYPE_UNSPECIFIED = 0; + COLLECTOR_TYPE_HISTOGRAM = 1; + COLLECTOR_TYPE_GAUGE = 2; + COLLECTOR_TYPE_COUNTER = 3; + COLLECTOR_TYPE_SUMMARY = 4; +} + +// Objective is a single (quantile, error) pair for Prometheus summary +// collectors. proto3 forbids float-keyed maps, so summary objectives are +// modelled as a repeated message rather than `map`. +message Objective { + double quantile = 1; + double error = 2; +} + +// Collector describes the shape of a single application-defined metric. +// Mirrors github.com/roadrunner-server/metrics/v6.Collector. +message Collector { + string namespace = 1; + string subsystem = 2; + CollectorType type = 3; + string help = 4; + repeated string labels = 5; + repeated double buckets = 6; + repeated Objective objectives = 7; +} + +// Metric is a single observation against an already-declared collector. +message Metric { + string name = 1; + double value = 2; + repeated string labels = 3; +} + +// NamedCollector wraps a Collector with its registry name; used only by +// Declare to register a new collector under that name. +message NamedCollector { + string name = 1; + Collector collector = 2; +} + +message AddRequest { Metric metric = 1; } +message SubRequest { Metric metric = 1; } +message ObserveRequest { Metric metric = 1; } +message SetRequest { Metric metric = 1; } + +message DeclareRequest { + NamedCollector collector = 1; +} + +message UnregisterRequest { + string name = 1; +} + +message Response { + bool ok = 1; +} + +// MetricsService exposes runtime metric mutation. All methods are write-side; +// scraping happens on the separate Prometheus HTTP endpoint configured under +// `metrics.address` and is not part of this RPC surface. +service MetricsService { + rpc Add(AddRequest) returns (Response); + rpc Sub(SubRequest) returns (Response); + rpc Observe(ObserveRequest) returns (Response); + rpc Set(SetRequest) returns (Response); + rpc Declare(DeclareRequest) returns (Response); + rpc Unregister(UnregisterRequest) returns (Response); +} diff --git a/roadrunner/api/resetter/v1/service.proto b/roadrunner/api/resetter/v1/service.proto new file mode 100644 index 0000000..e1d5b66 --- /dev/null +++ b/roadrunner/api/resetter/v1/service.proto @@ -0,0 +1,30 @@ +syntax = "proto3"; + +package resetter.v1; + +option go_package = "github.com/roadrunner-server/api-go/v6/resetter/v1;resetterV1"; +option php_metadata_namespace = "RoadRunner\\Resetter\\DTO\\V1\\GPBMetadata"; +option php_namespace = "RoadRunner\\Resetter\\DTO\\V1"; + +message ListPluginsRequest {} +message PluginsList { + repeated string plugins = 1; +} + +message ResetRequest { + string plugin = 1; +} + +message Response { + bool ok = 1; +} + +// ResetterService exposes the runtime reset surface for plugins that opt into +// the resetter contract (jobs, service, etc.). Listing is read-only; Reset +// triggers a per-plugin lifecycle reset. +service ResetterService { + rpc ListPlugins(ListPluginsRequest) returns (PluginsList) { + option idempotency_level = NO_SIDE_EFFECTS; + } + rpc Reset(ResetRequest) returns (Response); +} diff --git a/roadrunner/api/tcp/v1/service.proto b/roadrunner/api/tcp/v1/service.proto new file mode 100644 index 0000000..6730615 --- /dev/null +++ b/roadrunner/api/tcp/v1/service.proto @@ -0,0 +1,21 @@ +syntax = "proto3"; + +package tcp.v1; + +option go_package = "github.com/roadrunner-server/api-go/v6/tcp/v1;tcpV1"; +option php_metadata_namespace = "RoadRunner\\Tcp\\DTO\\V1\\GPBMetadata"; +option php_namespace = "RoadRunner\\Tcp\\DTO\\V1"; + +message CloseRequest { + string uuid = 1; +} + +message Response { + bool ok = 1; +} + +// TCPService exposes runtime control over open TCP connections handled by the +// tcp plugin. Close terminates a single connection identified by its UUID. +service TCPService { + rpc Close(CloseRequest) returns (Response); +} From cc0afc5e0a5fec5c94887f25d872f63928f3cd90 Mon Sep 17 00:00:00 2001 From: Valery Piashchynski Date: Tue, 12 May 2026 17:51:00 +0200 Subject: [PATCH 2/4] fix(proto): align informer ProcessState widths with service.v1.Status; correct TCP PHP namespace MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - informer/v1.ProcessState.pid: int64 → int32 (POSIX, matches service.v1.Status.pid) - informer/v1.ProcessState.cpu_percent: double → float (matches service.v1.Status.cpu_percent) - tcp/v1 PHP namespace: RoadRunner\Tcp → RoadRunner\TCP (matches HTTP/KV convention) Surfaced by Copilot review on PR #74. --- roadrunner/api/informer/v1/service.proto | 9 ++++++--- roadrunner/api/tcp/v1/service.proto | 4 ++-- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/roadrunner/api/informer/v1/service.proto b/roadrunner/api/informer/v1/service.proto index f008d30..75e53e3 100644 --- a/roadrunner/api/informer/v1/service.proto +++ b/roadrunner/api/informer/v1/service.proto @@ -7,14 +7,17 @@ option php_metadata_namespace = "RoadRunner\\Informer\\DTO\\V1\\GPBMetadata"; option php_namespace = "RoadRunner\\Informer\\DTO\\V1"; // ProcessState mirrors github.com/roadrunner-server/pool/v2/state/process.State — -// one entry per OS-level worker process managed by a plugin. +// one entry per OS-level worker process managed by a plugin. Field widths match +// the existing service.v1.Status convention (int32 pid, float cpu_percent) +// rather than the Go-source int64/float64; PIDs fit in int32 per POSIX, and a +// percentage value comfortably fits in float32. message ProcessState { - int64 pid = 1; + int32 pid = 1; int64 status = 2; uint64 num_execs = 3; int64 created = 4; uint64 memory_usage = 5; - double cpu_percent = 6; + float cpu_percent = 6; string command = 7; string status_str = 8; } diff --git a/roadrunner/api/tcp/v1/service.proto b/roadrunner/api/tcp/v1/service.proto index 6730615..429d44e 100644 --- a/roadrunner/api/tcp/v1/service.proto +++ b/roadrunner/api/tcp/v1/service.proto @@ -3,8 +3,8 @@ syntax = "proto3"; package tcp.v1; option go_package = "github.com/roadrunner-server/api-go/v6/tcp/v1;tcpV1"; -option php_metadata_namespace = "RoadRunner\\Tcp\\DTO\\V1\\GPBMetadata"; -option php_namespace = "RoadRunner\\Tcp\\DTO\\V1"; +option php_metadata_namespace = "RoadRunner\\TCP\\DTO\\V1\\GPBMetadata"; +option php_namespace = "RoadRunner\\TCP\\DTO\\V1"; message CloseRequest { string uuid = 1; From c2958821f418a300dc84b9ce144477659484c85f Mon Sep 17 00:00:00 2001 From: Valery Piashchynski Date: Tue, 12 May 2026 17:55:42 +0200 Subject: [PATCH 3/4] ci: add buf lint workflow Runs `buf lint` on every pull_request and master push. Uses the official bufbuild/buf-setup-action with the GITHUB_TOKEN to avoid GitHub API rate limits during buf installation. --- .github/workflows/buf-lint.yml | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 .github/workflows/buf-lint.yml diff --git a/.github/workflows/buf-lint.yml b/.github/workflows/buf-lint.yml new file mode 100644 index 0000000..97d8f00 --- /dev/null +++ b/.github/workflows/buf-lint.yml @@ -0,0 +1,23 @@ +name: 'Buf Lint' + +on: + pull_request: + push: + branches: + - master + +jobs: + lint: + name: 'buf lint' + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Set up buf + uses: bufbuild/buf-setup-action@v1 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + + - name: Lint protofiles + run: buf lint From 41847c0b026ddd3056d4357097d95befd86153af Mon Sep 17 00:00:00 2001 From: Valery Piashchynski Date: Tue, 12 May 2026 17:57:59 +0200 Subject: [PATCH 4/4] ci: fetch git submodules in buf-lint workflow third_party/api is a submodule (temporalio/api); without it the temporal proto's external imports don't resolve and buf lint fails. --- .github/workflows/buf-lint.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/buf-lint.yml b/.github/workflows/buf-lint.yml index 97d8f00..b9f3138 100644 --- a/.github/workflows/buf-lint.yml +++ b/.github/workflows/buf-lint.yml @@ -13,6 +13,8 @@ jobs: steps: - name: Checkout uses: actions/checkout@v4 + with: + submodules: recursive - name: Set up buf uses: bufbuild/buf-setup-action@v1