Skip to content

feat: GraphQL subscriptions via Strawberry + Channels (#764)#816

Open
Jessepriase wants to merge 1 commit into
SoroScan:mainfrom
Jessepriase:feat/graphql-subscriptions
Open

feat: GraphQL subscriptions via Strawberry + Channels (#764)#816
Jessepriase wants to merge 1 commit into
SoroScan:mainfrom
Jessepriase:feat/graphql-subscriptions

Conversation

@Jessepriase

Copy link
Copy Markdown
Contributor

Implementation was already in place across schema.py, asgi.py and subscription_middleware.py. This commit completes the issue by:

requirements.txt:

  • Upgrade strawberry-graphql to strawberry-graphql[channels]==0.289.0 to formally declare the channels extras dependency (channels, daphne, channels_redis were already present individually)

test_graphql_subscriptions.py — integration tests covering all acceptance criteria without requiring a live WebSocket stack:

Schema shape

  • Subscription type exists and is named 'Subscription'
  • contractEvents field is present with contractId argument
  • Existing notifications field is still present

Resolver type safety

  • contract_events is an AsyncGenerator (async def ... yield)
  • notifications is also an AsyncGenerator

Channel lifecycle

  • group_add called with 'events_{contract_id}' group name on subscribe
  • group_discard called in finally block when generator is closed
  • group_discard called even when channel layer raises mid-loop
  • No channel layer configured: resolver exits gracefully without error

End-to-end event flow

  • Message published to channel group causes resolver to yield ContractEvent
  • ContractEvent.DoesNotExist is swallowed; generator continues

HTTP query regression

  • contracts, events, and introspection queries all still work

Rate limiting (SubscriptionRateLimitMiddleware)

  • Allows up to 5 concurrent connections per IP
  • Rejects 6th connection with close code 4429
  • Allows connections below the limit
  • Decrements counter on close
  • IP extraction: X-Forwarded-For takes precedence over client address
  • Non-WebSocket scopes bypass middleware unchanged

ASGI routing

Implementation was already in place across schema.py, asgi.py and
subscription_middleware.py. This commit completes the issue by:

requirements.txt:
- Upgrade strawberry-graphql to strawberry-graphql[channels]==0.289.0
  to formally declare the channels extras dependency (channels, daphne,
  channels_redis were already present individually)

test_graphql_subscriptions.py — integration tests covering all
acceptance criteria without requiring a live WebSocket stack:

  Schema shape
  - Subscription type exists and is named 'Subscription'
  - contractEvents field is present with contractId argument
  - Existing notifications field is still present

  Resolver type safety
  - contract_events is an AsyncGenerator (async def ... yield)
  - notifications is also an AsyncGenerator

  Channel lifecycle
  - group_add called with 'events_{contract_id}' group name on subscribe
  - group_discard called in finally block when generator is closed
  - group_discard called even when channel layer raises mid-loop
  - No channel layer configured: resolver exits gracefully without error

  End-to-end event flow
  - Message published to channel group causes resolver to yield ContractEvent
  - ContractEvent.DoesNotExist is swallowed; generator continues

  HTTP query regression
  - contracts, events, and introspection queries all still work

  Rate limiting (SubscriptionRateLimitMiddleware)
  - Allows up to 5 concurrent connections per IP
  - Rejects 6th connection with close code 4429
  - Allows connections below the limit
  - Decrements counter on close
  - IP extraction: X-Forwarded-For takes precedence over client address
  - Non-WebSocket scopes bypass middleware unchanged

  ASGI routing
  - GraphQLWSConsumer importable from strawberry.channels
  - application is a ProtocolTypeRouter
  - Schema object exposes a subscription type
@drips-wave

drips-wave Bot commented Jun 27, 2026

Copy link
Copy Markdown

@Jessepriase Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

@DokaIzk

DokaIzk commented Jun 28, 2026

Copy link
Copy Markdown
Collaborator

@Jessepriase CI checks are failing, kindly resolve

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.

GraphQL Subscriptions via Strawberry + Channels

2 participants