3 Commits
Author SHA1 Message Date
Conner Mo 9996a16f83 perf(channels): shard outbound dispatch per conversation
A single dispatch goroutine delivered every reply in the process — every
channel, every user — each Send blocking the next. One media upload of a
few seconds froze all outbound traffic for that long, and sustained
throughput was capped at one Send round-trip regardless of lane capacity.

The ordering that loop actually protected is per-conversation: a run emits
block replies, retry notices and a final answer to one ChatID, and those
must arrive in that order. A global order was never required.

Dispatch now shards on channel+ChatID. A conversation always maps to the
same shard and is delivered serially there, so the ordering guarantee is
unchanged, while unrelated conversations proceed in parallel.
GOCLAW_OUTBOUND_SHARDS tunes the worker count (default 8).

Temp media needed a real fix to go with it. Serial dispatch deduped it
implicitly — the first delivery removed the file, and a later message
carrying the same path found os.Stat failing and skipped it. Across
concurrent shards that check alone is a TOCTOU race, so claims are now
taken atomically and released after the send.

Also makes the pool limits that bound this path configurable, defaults
unchanged: GOCLAW_PG_MAX_OPEN_CONNS / GOCLAW_PG_MAX_IDLE_CONNS, and
GOCLAW_HTTP_MAX_IDLE_CONNS / GOCLAW_HTTP_MAX_IDLE_CONNS_PER_HOST. The
per-host limit binds when one provider takes nearly all traffic: every
request past it pays a fresh TCP+TLS handshake, which a deployment
raising LaneMain needs to be able to lift.
2026-07-22 14:14:02 +08:00
thotam 25eaa0166f fix(backup): repair tenant backup/restore (config_secrets order, hooks registry, restore conn check) (#1357)
Closes #1076, #1338.

Fix A — tenant backup aborted with SQLSTATE 42703 "column id does not
exist" because exportQuery() hardcoded ORDER BY id. Several tenant-scoped
tables have composite PKs and no id column. Add a TableDef.OrderBy field,
honor it in exportQuery(), and set it for every id-less registry table:
config_secrets, agent_team_members, tenant_hook_budget, system_configs,
builtin_tool_tenant_configs, skill_tenant_configs, user_agent_profiles.

Fix B — hooks, tenant_hook_budget and webhook config were missing from
the backup registry, silently dropping their data on backup/restore. Add
hooks, tenant_hook_budget, webhooks (preserve) plus the hook_agents junction
(via ParentJoin through hooks, composite PK), and mark hook_executions and
webhook_calls as ephemeral in the skipped list.

Fix C — restoring on a fresh server failed with "N active DB connection(s)
detected" because the gateway's own pool connections were counted as active
clients. Tag pool connections with application_name='goclaw' (pg.OpenDB) and
exclude them in CheckActiveConnections; genuine external clients still block.

Adds unit + integration regression tests, including an export-over-every-
registered-table test that surfaced the additional id-less tables.
2026-07-05 11:56:36 +07:00
Viet TranandClaude Opus 4.6 f3f4c67b36 Initial commit: GoClaw AI agent gateway
Multi-agent AI gateway with WebSocket RPC, HTTP API, and messaging channel integrations.
Go port of OpenClaw with multi-tenant PostgreSQL, per-user isolation, security hardening,
and production observability.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 14:58:07 +07:00