-
Notifications
You must be signed in to change notification settings - Fork 0
Closed
Description
問題の説明
現在の振る舞い
- 2つのノードがグループに参加している
- ホストノードがそのグループに対してdissolveGroupを実行する
- もう一方のノードは変化せず、そのグループに参加し続けている状態になる
期待される振る舞い
- dissolveGroupを実行すると、参加しているノードすべてがそれを検知してdisconnected状態に遷移する
現在の実装の分析
バックエンドの実装状況
✅ dissolveGroup mutationは完全に実装済み
lambda/use_cases/dissolve_group.rbにて実装- DynamoDBから全てのグループデータを削除(メタデータ、ノード、ステータス)
- ホスト権限の検証あり
✅ onGroupDissolve subscriptionが自動的にトリガーされる
graphql/schema.graphqlで定義- AppSyncが自動的にgroupIdとdomainでフィルタリングして購読者に通知
- リアルタイムでメンバーに通知される仕組みは実装済み
✅ 既存のテストカバレッジ
- Unit tests:
spec/unit/use_cases/dissolve_group_spec.rb(88 lines) - Integration tests:
spec/requests/dissolve_group_spec.rb(137 lines) - ただし、subscription通知のE2Eテストは未実装
問題の原因仮説
1. クライアント側の実装不足
- フロントエンド(Smalruby3-GUI)が
onGroupDissolvesubscription を購読していない可能性 - subscriptionを購読していても、通知受信時の状態更新処理が未実装の可能性
2. Subscriptionの信頼性問題
- WebSocket接続が切れている場合のフォールバック機構がない
- ネットワーク不安定時に通知が届かない可能性
- クライアント側でsubscription接続の監視が不十分
提案する解決策
Option 1: クライアント側の実装確認・修正 ⭐️ 推奨
フロントエンド(Smalruby3-GUI)で以下を実装:
// onGroupDissolve subscriptionを購読
const subscription = API.graphql({
query: onGroupDissolveSubscription,
variables: { groupId, domain }
}).subscribe({
next: (data) => {
console.log('Group dissolved:', data);
// disconnected状態に遷移
updateNodeState('disconnected');
// UIを更新
showDisconnectedMessage('Group has been dissolved by host');
},
error: (error) => {
console.error('Subscription error:', error);
}
});メリット:
- リアルタイムで即座に反応
- バックエンドの変更不要
- AppSyncの機能を最大限活用
デメリット:
- WebSocket切断時に通知が届かない可能性
Option 2: ポーリングによるフォールバック
定期的にグループの存在確認を実装:
// メインの通知はsubscriptionで受け取る
const subscription = subscribeToGroupDissolve(groupId, domain);
// フォールバック: 定期的にグループの存在確認
const pollInterval = setInterval(async () => {
const group = await getGroup(groupId, domain);
if (!group && currentState === 'connected') {
console.log('Group no longer exists (detected by polling)');
updateNodeState('disconnected');
showDisconnectedMessage('Connection lost');
}
}, 10000); // 10秒ごとメリット:
- subscription失敗時のフォールバックとして機能
- より確実にdisconnected状態に遷移できる
デメリット:
- ポーリング間隔分の遅延が発生
- 不要なAPI呼び出しが増える
Option 3: バックエンドでの明示的な通知レコード
DynamoDBに各メンバー向けの通知レコードを作成し、クライアントが次回のデータ取得時に確実に検知できるようにする。
# lambda/use_cases/dissolve_group.rb
def execute(group_id:, domain:, host_id:)
# ... existing code ...
# Get all member nodes before dissolution
members = @repository.find_group_members(group_id, domain)
# Dissolve the group
@repository.dissolve_group(group_id, domain)
# Create notification records for each member
members.each do |member|
@repository.create_notification(
node_id: member.node_id,
type: 'GROUP_DISSOLVED',
group_id: group_id,
domain: domain,
timestamp: Time.now.iso8601
)
end
# ... existing code ...
endメリット:
- subscription失敗時でも確実に通知が届く
- 通知履歴が残る
デメリット:
- バックエンドの変更が必要
- DynamoDBへの追加書き込みが発生
- クライアント側で通知の取得・処理ロジックが必要
実装方針の推奨
推奨アプローチ: Option 1 + Option 2のハイブリッド
- Primary:
onGroupDissolvesubscriptionを実装(リアルタイム通知) - Fallback: 定期的なポーリングを実装(信頼性向上)
これにより、以下を実現:
- リアルタイム性を確保(subscription)
- 信頼性を確保(polling fallback)
- バックエンドの変更不要
テスト戦略
E2Eテストの実装(TDD)
新規テストファイル: spec/e2e/dissolve_group_notification_spec.rb
require 'spec_helper'
describe "dissolveGroup E2E notification test" do
let(:domain) { "test.example.com" }
let(:group_name) { "test-group-#{Time.now.to_i}" }
let(:host_id) { "host-node-#{SecureRandom.uuid}" }
let(:member_id) { "member-node-#{SecureRandom.uuid}" }
it "2つのノードが接続後、dissolve groupで両方がdisconnected状態になる" do
# Setup: Create group
group = create_test_group(group_name, host_id, domain)
group_id = group["id"]
# Setup: Member joins group
join_test_node(group_id, domain, member_id, "Member Node")
# Setup: Both nodes subscribe to onGroupDissolve
host_notifications = []
member_notifications = []
host_subscription = subscribe_to_group_dissolve(group_id, domain) do |data|
host_notifications << data
end
member_subscription = subscribe_to_group_dissolve(group_id, domain) do |data|
member_notifications << data
end
# Wait for subscriptions to be established
sleep 2
# Action: Host dissolves the group
response = execute_graphql(dissolve_group_mutation, {
groupId: group_id,
domain: domain,
hostId: host_id
})
expect(response["errors"]).to be_nil
expect(response["data"]["dissolveGroup"]["groupId"]).to eq(group_id)
# Wait for notifications to propagate
sleep 3
# Assertions: Both nodes should have received notification
expect(host_notifications).not_to be_empty, "Host should receive dissolution notification"
expect(member_notifications).not_to be_empty, "Member should receive dissolution notification"
expect(host_notifications.first["groupId"]).to eq(group_id)
expect(member_notifications.first["groupId"]).to eq(group_id)
# Verify group is actually deleted
get_response = execute_graphql(get_group_query, { groupId: group_id, domain: domain })
expect(get_response["data"]["getGroup"]).to be_nil
# Cleanup subscriptions
host_subscription.unsubscribe
member_subscription.unsubscribe
end
it "ホストのみがdissolveした場合、メンバーも通知を受け取る" do
# Similar test focusing on member-only notification
end
it "subscription接続が切れている場合でも、ポーリングでdisconnected状態に遷移する" do
# Test fallback polling mechanism (if implemented)
end
endテスト実装のステップ
-
subscribe_to_group_dissolveヘルパーメソッドを実装 - テストを実行して失敗することを確認(RED)
- フロントエンドでsubscription購読を実装
- テストが成功することを確認(GREEN)
実装ステップ
Phase 1: 現状確認
- Smalruby3-GUIの現在のメッシュネットワーク実装を確認
- GraphQLクライアントの実装を確認
- 既存のsubscription実装があるか確認
Phase 2: バックエンドテストの実装(TDD)
-
spec/e2e/dissolve_group_notification_spec.rbを作成 - WebSocket subscription用のテストヘルパーを実装
- テストを実行して失敗することを確認(RED)
Phase 3: フロントエンド実装
-
onGroupDissolvesubscriptionの購読実装 - 通知受信時の状態遷移処理の実装
- disconnected状態のUI表示を実装
- エラーハンドリングの実装
Phase 4: フォールバック実装(Optional)
- ポーリングによるグループ存在確認の実装
- subscription失敗時のフォールバック処理
Phase 5: 検証
- E2Eテストが成功することを確認(GREEN)
- 手動テストで動作確認
- ドキュメント更新
関連ファイル
Backend
lambda/use_cases/dissolve_group.rb- dissolveGroupの実装graphql/schema.graphql- onGroupDissolve subscription定義spec/requests/dissolve_group_spec.rb- 既存の統合テストSUBSCRIPTIONS.md- subscription仕様のドキュメント
Frontend(想定)
gui/smalruby3-gui/src/components/mesh-network/- メッシュネットワーク関連コンポーネントgui/smalruby3-gui/src/lib/mesh-network-client.js- GraphQL クライアントgui/smalruby3-gui/src/lib/mesh-network-subscriptions.js- Subscription管理
期待される成果
- ✅ ホストがdissolveGroupを実行した際、すべてのメンバーノードがリアルタイムで通知を受け取る
- ✅ 通知を受け取ったノードは自動的にdisconnected状態に遷移する
- ✅ UI上でグループ解散の通知が表示される
- ✅ E2Eテストで動作が保証される
- ✅ ネットワーク不安定時でもフォールバック機構により確実に状態遷移する
🤖 Generated with Claude Code
Co-Authored-By: Claude Sonnet 4.5 noreply@anthropic.com
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels