feat: add getkeys-all-ws config operation to avoid oversized responses (#1058)

With many workspaces, the getvalues-all-ws response for types with
large values (e.g. prompt templates) exceeds Pulsar's max message size.

Add a getkeys-all-ws operation that returns workspace/key pairs without
values. Processors now use this to discover which workspaces have config
of a given type, then fetch values per-workspace. Each individual
response stays within message size limits.
This commit is contained in:
cybermaggedon 2026-07-23 12:13:54 +01:00 committed by GitHub
parent bc30c81d53
commit eb059707f0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 67 additions and 8 deletions

View file

@ -147,10 +147,13 @@ class AsyncProcessor:
async def _fetch_type_all_workspaces(self, client, config_type):
"""Fetch config values of a single type across all workspaces.
Returns dict of {workspace: {key: value}}."""
Uses getkeys-all-ws to discover workspaces, then fetches values
per-workspace to avoid oversized responses."""
# Step 1: get workspace/key pairs (small response)
resp = await client.request(
ConfigRequest(
operation="getvalues-all-ws",
operation="getkeys-all-ws",
type=config_type,
),
timeout=10,
@ -158,11 +161,21 @@ class AsyncProcessor:
if resp.error:
raise RuntimeError(f"Config error: {resp.error.message}")
grouped = {}
version = resp.version
# Group keys by workspace
workspaces = set()
for v in resp.values:
ws = grouped.setdefault(v.workspace, {})
ws[v.key] = v.value
return grouped, resp.version
workspaces.add(v.workspace)
# Step 2: fetch values per workspace
grouped = {}
for ws in workspaces:
kv = await self._fetch_type_workspace(client, ws, config_type)
if kv:
grouped[ws] = kv
return grouped, version
# This is called to start dynamic behaviour.
# Implements the subscribe-then-fetch pattern to avoid race conditions.

View file

@ -11,6 +11,7 @@ from ..core.primitives import Error
# list(workspace, type) -> (version, directory)
# getvalues(workspace, type) -> (version, values)
# getvalues-all-ws(type) -> (version, values with workspace field)
# getkeys-all-ws(type) -> (version, values with workspace+key, no value)
# put(workspace, values) -> ()
# delete(workspace, keys) -> ()
# config(workspace) -> (version, config)
@ -36,8 +37,8 @@ class ConfigValue:
@dataclass
class ConfigRequest:
# Operations: get, list, getvalues, getvalues-all-ws, delete, put,
# config
# Operations: get, list, getvalues, getvalues-all-ws,
# getkeys-all-ws, delete, put, config
operation: str = ""
# Workspace scope — required on all operations except