Skip to content

Websocket test - #21

Draft
damian-rakus wants to merge 37 commits into
mainfrom
feature/damianra/websocket-test
Draft

Websocket test#21
damian-rakus wants to merge 37 commits into
mainfrom
feature/damianra/websocket-test

Conversation

@damian-rakus

Copy link
Copy Markdown
Collaborator

No description provided.

jensneuse and others added 30 commits June 19, 2026 12:11
Allows custom modules to mark a request as having a wildcard scope that
satisfies all @requiresScopes checks. Authentication is still enforced.

Closes wundergraph#2490

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Replace require.Contains with exact require.Equal assertions
- Add test for RejectOperationIfUnauthorized + wildcard scope
- Clarify doc comment: authentication is a prerequisite for wildcard

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Move wildcardScopeKey type to authorizer.go next to hasWildcardScope
- Replace raw JSON string assertions with structured graphQLResponse
  type for readable test assertions

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…eak (#2)

* fix(router): clear slowplancache entries on Close to prevent memory leak

During config reloads, ristretto's OnEvict callback pushes plan entries
into the slowplancache. Each entry holds a pointer to the schema AST
document (~200MB). When slowplancache.Close() is called, it stops the
background goroutine but never clears the sync.Map entries, keeping old
schemas pinned in memory until the entire Cache struct is GC'd — which
may be delayed by goroutines still referencing the owning graphMux.

Clear all entries in Close() so that references to expensive objects
(like *ast.Document) are released immediately.

* fix(router): guard slowplancache Close() clearing with mondaytweaks flag

Add router/pkg/mondaytweaks package (same pattern as graphql-go-tools)
for compile-time feature flags. Guard the entry-clearing fix behind
mondaytweaks.ClearSlowPlanCacheOnClose so it's easy to upstream later.
* fix(router): release schema refs on config reload to prevent memory leak

Stop storing schemaDocument in cached planWithMetaData entries so plan
caches no longer pin the old router schema AST (~200MB) after CDN reloads.
Also call OnRouterConfigReload before building a new graph server so
slow-plan cache entries are extracted while the old graphMux is still
referenced, matching the supervisor restart path.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(router): drain WS subs and skip plan cache OnEvict on mux shutdown

Disable ristretto OnEvict migration into slowplancache when a graphMux is
shutting down, since Close() clears every entry and the fallback cache is
about to be closed anyway. Close websocket subscriptions synchronously
before plan caches so preparedPlan and executor refs are released first.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(router): register heap pprof handlers for in-use profiling

Expose /debug/pprof/heap and related routes on the pprof server so
forced-GC heap snapshots (heap?gc=1) work for memory leak diagnosis.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(router): re-read PPROF_ADDR from env after flag.Parse

Flag defaults are captured at package init before embedders set PPROF_ADDR
in main(), so platform-api ensurePprofAddr had no effect. Re-read env after
flag.Parse() matches the existing CONFIG_PATH pattern.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(router): release executor schema refs and reduce upstream WS overhead on reload

Executor.Close() nils federation schema AST held after graph mux shutdown.
Share one upstream subscription client across subgraph factories and disable
upstream ping loops when client WebSocket is disabled.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(router): use noop upstream subscription client when subscriptions unused

Skip WSTransport/SSE initialization when the router schema has no
subscription root fields or when client WebSocket and pubsub events are
both disabled.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(router): nil graphMux caches after shutdown to allow GC on reload

Close and drop Ristretto cache pointers, wsHandler, and mux after graphMux
shutdown, and remove shut-down muxes from graphMuxList. Local benchmark:
~74 MB/reload → ~12 MB/reload retained inuse (same-content manifest reloads).

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(router): skip unchanged manifest reloads and release stale execution config

Hash mapper.json before re-assembling; skip reload when content is
unchanged (mtime-only touches). After a successful reload, swap
staticExecutionConfig and proto.Reset the previous config so decoded
protojson strings can be collected.

* fix(router): reuse graph muxes on manifest reload and release shutdown refs

Pass Changes/Hashes from mapper.json graph hashes on the manifest watcher
path so unchanged base or feature-flag muxes survive config reloads.
Nil graphServer and graphMux metric fields after shutdown to drop retained
references sooner.

* Revert "fix(router): reuse graph muxes on manifest reload and release shutdown refs"

This reverts commit 2c32b45.

* chore(router): drop profiling/pyroscope changes from PR

Remove late env re-read for PPROF/PYROSCOPE in main.go and extra pprof
handlers in profile.go so this PR stays focused on config reload fixes.

* fix(router): gate memory-leak fixes behind mondaytweaks constants

Centralize all monday.com config-reload leak fixes in mondaytweaks.go so
they are easy to audit and disable individually. Restore profiling helpers
from stash behind separate tweak flags.

* chore(router): drop profiling and pyroscope mondaytweaks

Remove PPROF/PYROSCOPE env re-read, heap pprof routes, and Pyroscope
name/tag helpers so the PR stays focused on config reload memory fixes.

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
…flag) (#7)

* perf(router): size-aware execution-plan cache eviction (mondaytweaks flag)

The execution-plan Ristretto cache evicts by entry count (every entry costs 1,
MaxCost = ExecutionPlanCacheSize), so a single structurally-unique aliased-batch
mutation plan occupies one slot regardless of its true retained size. On US
cluster group 02 a burst of such giant plans could evict thousands of small hot
plans while collectively pinning most of the plan-cache heap — the dominant
driver of the 02 vs 01 RSS gap (plan cache ~16% of heap on 02 vs ~4% on 01).

Adds mondaytweaks.SizeAwarePlanCache (default off, canary-first): when enabled,
MaxCost becomes ExecutionPlanCacheSize * PlanCacheSizeAwareBudgetPerSlotBytes
(a byte budget) and each entry is charged estimatePlanCacheCost — a cheap
O(number-of-slices) estimate of the retained heap keyed off operationDocument
(always populated) plus the raw operation bytes. Giant plans then cost tens of
slots and evict first, and total plan-cache heap is bounded to a predictable
ceiling. NumCounters stays keyed to the expected entry count for TinyLFU.

Default off so existing count-based behaviour (and the plan-fallback-cache tests
that rely on ExecutionPlanCacheSize=1 forcing single-entry eviction) is
unchanged; intended to be enabled as a per-cluster canary starting with 02.

* perf(router): enable size-aware plan cache by default with per-instance opt-out

Flip mondaytweaks.SizeAwarePlanCache on by default so the execution-plan cache
evicts by estimated retained heap (byte budget) instead of entry count.

Defaulting it on would break the plan-fallback-cache integration tests, which
rely on count-based single-entry eviction (ExecutionPlanCacheSize=1) to force
eviction and exercise the fallback trigger. Since router-tests run with -race,
toggling the global flag inside those parallel tests is not safe.

Instead add a per-instance opt-out, config.EngineExecutionConfiguration.
DisableSizeAwarePlanCache (programmatic only, no env/yaml binding). Both the
cache-budget computation (graph_server) and the plan-cache Set cost
(operation_planner) now consult sizeAwarePlanCacheEnabled(cfg) so cost and
MaxCost always agree, and the fallback tests set DisableSizeAwarePlanCache=true
to pin deterministic count-based eviction without mutating the global.

Production leaves the override false and follows the mondaytweaks default (on).
…undergraph#3035

Local reload benchmarks showed ~7.6 MB/reload retained with flags off vs
pre-fix ~260 MB, so the flag-guarded reload cleanup is redundant with
upstream graphMux closure fixes. Drop the eight memory-leak toggles and
their guarded code while keeping behavior/perf tweaks and the structural
schemaDocument removal in cached plans.
Turn off the three subscription/websocket-disablement compile-time flags,
reverting to upstream default subscription-client behavior:
- ShareUpstreamSubscriptionClient
- UseNoopUpstreamSubscriptionClientWhenUnused
- DisableUpstreamSubscriptionPingWhenClientWebSocketDisabled

Suspected of interfering with CDN config hot reload. Leaves perf/observability
tweaks (SizeAwarePlanCache, fetch-count field) untouched.
…12)

SwapGraphServer shuts the previous graph server down synchronously on the
config-poller goroutine with an unbounded ctx. graphServer.Shutdown drains
in-flight requests via wait() (polls inFlightRequests, no independent timeout),
so a single stuck request — e.g. a handler blocked on a dead-client write
(WriteTimeout=0) or a custom module's own HTTP call — freezes the entire config
pipeline. Production showed in-flight-drain stalls up to 1h21m, which:
  - froze CDN config hot-reload → pods served stale schema for hours (#3286)
  - pinned the old generation's schema AST + ristretto caches + protojson in
    memory, driving a GC mark-phase storm and planning-latency spikes.

Behind mondaytweaks.AsyncBoundedOldGraphServerShutdown (default on): run the old
server's Shutdown off the poller goroutine and bound the drain by the configured
grace_period (fallback 90s > 60s subgraph request_timeout when unset), via
context.WithoutCancel + WithTimeout. New traffic already routes to the swapped-in
server, so abandoning a stuck old-server request after the drain window is safe
and lets reloads proceed + releases the old generation.

Also re-enable DisableUpstreamSubscriptionPingWhenClientWebSocketDisabled: prod
runs websocket.enabled=false, yet a goroutine profile showed WSTransport.pingLoop
at ~65% of all goroutines (1.5M) accumulating across reloads. Zeroing PingInterval
when client WS is disabled stops that leak.
…estimator (#19)

* fix(router): count fetch tree and response fields in plan cache cost estimator

* test(router): cover fetch tree and response field counting in plan cache cost

* feat(router): gate plan cache tree-walk cost behind PlanCacheCostCountsPlanTree flag

* feat(mondaytweaks): gate graphql Source caching behind ReuseGraphQLSource flag

* chore(router): replace graphql-go-tools with local pool-graphql-source worktree

* Revert "chore(router): replace graphql-go-tools with local pool-graphql-source worktree"

This reverts commit e940ef7.

* fix(mondaytweaks): move ReuseGraphQLSource flag to graphql-go-tools package
…ndedOldGraphServerShutdown, useNoopUpstreamSubscriptionClientWhenUnused flags

All three were disabled (false) or reverted to upstream defaults due to
suspected interference with CDN config hot-reload. Remove them along
with their supporting infrastructure: noop subscription client files,
WebSocketConfiguration field in ExecutorBuildOptions, gracePeriod
machinery in http_server, and the sharedSubscriptionClient path in
factoryresolver.
- Inline subscriptionClientForFactory (trivial wrapper after ShareUpstreamSubscriptionClient removal)
- Revert NewWebsocketMiddleware second return value (*WebsocketHandler unused)
- Revert demo.config.yaml to upstream (local dev additions)
budziam and others added 7 commits July 20, 2026 13:59
…form

The newSubscriptionClient() extraction was introduced to support the
shared/noop subscription client paths, both of which have been removed.
Inline the construction back to match upstream exactly.
…ment

planFallbackCache is conditionally created and slowplancache.Set has a
nil receiver guard, but that's non-obvious. The comment explaining why
the call is safe was dropped when SkipPlanCacheOnEvictDuringMuxShutdown
was removed; restore it.
The sync-handler tracking and ShutdownConnections were already removed in
9455ffe. Remove the leftover closeOnce field and Do wrapper to fully
revert websocket.go to upstream.
@github-actions

github-actions Bot commented Sep 7, 2026

Copy link
Copy Markdown

aws-lambda-router - uncommitted changes detected

Seems like you forgot to commit some code. Possible causes:

  • Generated code not part of the PR, fix with: make generate and commit the changes
  • Dependency mismatch for tools (protoc, etc). Ensure your local machine has same versions of tools as CI does
  • Formatting drift, fix with make format aws-lambda-router / pnpm format aws-lambda-router

Dirty files
  • connect-go/gen/proto/wg/cosmo/node/v1/node.pb.go
  • router/gen/proto/wg/cosmo/node/v1/node.pb.go

@github-actions

github-actions Bot commented Sep 7, 2026

Copy link
Copy Markdown

connect-go - uncommitted changes detected

Seems like you forgot to commit some code. Possible causes:

  • Generated code not part of the PR, fix with: make generate and commit the changes
  • Dependency mismatch for tools (protoc, etc). Ensure your local machine has same versions of tools as CI does
  • Formatting drift, fix with make format connect-go / pnpm format connect-go

Dirty files
  • connect-go/gen/proto/wg/cosmo/node/v1/node.pb.go
  • router/gen/proto/wg/cosmo/node/v1/node.pb.go

@github-actions

github-actions Bot commented Sep 7, 2026

Copy link
Copy Markdown

Router-nonroot image scan failed

❌ Security vulnerabilities found in image:

ghcr.io/mondaycom/cosmo/router:sha-91e4f2b34c42c3ce9d0ba4304b33ffe910e2f497-nonroot

Please check the security vulnerabilities found in the PR.

If you believe this is a false positive, please add the vulnerability to the .trivyignore file and re-run the scan.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants