Skip to content

Conversation

@takaokouji
Copy link
Contributor

Summary

Implements polling-based event notification as a fallback for environments where WebSocket connections are blocked by network firewalls.

Background

In corporate or educational network environments, WebSocket connections (wss://) are often blocked by security policies. This PR adds a polling-based protocol that allows the Mesh extension to work in such environments while maintaining WebSocket support for environments where it's available.

Implementation

Protocol Selection (Host)

  1. WebSocket Test: Host tests WebSocket connectivity when creating a group
  2. Protocol Flag: Sets useWebSocket flag based on test result
  3. Server Storage: Server stores the flag in the Group entity
  4. Cost Optimization: Prioritizes WebSocket when available

Protocol Selection (Member)

  1. Join Group: Member receives useWebSocket flag from joinGroup response
  2. Protocol Switch: Switches event transmission and reception methods accordingly

Two Protocols

Protocol A: WebSocket (Existing)

  • Event transmission: fireEventsByNode mutation (None DataSource)
  • Event reception: onMessageInGroup subscription (WebSocket)
  • Characteristics: Real-time, low cost

Protocol B: Polling (New)

  • Event transmission: recordEventsByNode mutation (saves to DynamoDB)
  • Event reception: getEventsSince query (polling every 2 seconds)
  • Characteristics: No WebSocket required, firewall-compatible

Key Technical Details

Server-side Timestamp Management

  • recordEventsByNode generates timestamps on the server side using util.time.nowISO8601()
  • Client-side event.firedAt is not used
  • Reason: 1+ second delay exists from device event firing to recordEventsByNode call
  • Benefits:
    • Time consistency (no client clock skew)
    • Order guarantee (request reception order)
    • Consistency with since parameter

Cursor-based Pagination

  • Event.cursor field contains Sort Key (SK)
  • RecordEventsPayload.nextSince returns next cursor value
  • Client uses cursor or nextSince as next since parameter

Changes

Server-side (infra/mesh-v2)

  • Added useWebSocket parameter to createGroup mutation
  • Added recordEventsByNode mutation (new)
  • Added getEventsSince query (new)
  • Added environment variables: MESH_EVENT_TTL_SECONDS, MESH_POLLING_INTERVAL_SECONDS
  • Updated Group and Node types with useWebSocket and pollingIntervalSeconds fields
  • Added cursor field to Event type

Client-side (gui/scratch-vm)

  • Added testWebSocket() method to detect protocol availability
  • Updated createGroup() to include useWebSocket parameter
  • Updated joinGroup() to retrieve useWebSocket from response
  • Implemented polling functionality: startPolling(), stopPolling(), pollEvents()
  • Updated event firing to use FIRE_EVENTS or RECORD_EVENTS based on protocol
  • Added unit tests for polling functionality

Test Coverage

Unit Tests (scratch-vm)

  • pollEvents fetches and handles events correctly
  • fireEventsBatch uses RECORD_EVENTS when useWebSocket is false
  • Cursor-based pagination works correctly

Integration Tests (mesh-v2)

  • Group creation with useWebSocket flag
  • Event recording with server-side timestamps
  • Event retrieval with cursor-based pagination

Configuration

Default Values

  • MESH_EVENT_TTL_SECONDS: 10 (events auto-delete after 10 seconds)
  • MESH_POLLING_INTERVAL_SECONDS: 2 (poll every 2 seconds)

Cost Optimization

  • WebSocket priority: Uses WebSocket when available (existing protocol)
  • Short TTL: Polling events auto-delete after 10 seconds to minimize storage cost
  • Appropriate polling interval: 2-second interval balances real-time性 and cost

Related Issue

Fixes #14

Sub-module PRs

  • smalruby/infra/mesh-v2: (Will create after this PR)
  • smalruby/scratch-vm: (Will create after this PR)

🤖 Generated with Claude Code

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.

feat: WebSocket 接続失敗時のポーリングによるイベント通知

2 participants