Skip to content

Commit 4eda6a8

Browse files
committed
refactor: implement shared network architecture for service coordination and streamline startup process
1 parent ed4916d commit 4eda6a8

9 files changed

Lines changed: 334 additions & 128 deletions

File tree

AGENTS.md

Lines changed: 59 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -52,11 +52,55 @@ The bundle integrates four Anytype sync services into a single binary:
5252

5353
### Critical: Service Startup Order
5454

55-
**ORDER MATTERS!** Services must start in this exact order (`cmd/start.go:83-87`):
56-
1. **Coordinator** - provides network coordination for all other services
57-
2. **Consensus, File, Sync** - can start in any order (all depend on coordinator)
55+
**ORDER MATTERS!** Services must start in this exact order:
56+
1. **Coordinator** - MUST start first (provides shared network stack for all services)
57+
2. **Consensus, File, Sync** - start after coordinator (reuse its network stack)
5858

59-
If coordinator doesn't start first, other services will fail to connect.
59+
The coordinator creates the network infrastructure (TCP/UDP listeners, DRPC mux, connection pool).
60+
Other services extract and reuse these components via `SharedNetworkManager`.
61+
62+
### Shared Network Architecture
63+
64+
**Key Innovation**: Instead of each service creating its own network stack, all services share ONE network infrastructure:
65+
66+
```
67+
Coordinator App (Primary)
68+
├── Creates network stack
69+
│ ├── yamux (TCP listener on port 33010)
70+
│ ├── quic (UDP listener on port 33020)
71+
│ ├── server (DRPC multiplexer)
72+
│ ├── pool (connection pool)
73+
│ └── peerservice (peer management)
74+
└── Registers CoordinatorService RPC handlers
75+
76+
SharedNetworkManager
77+
├── Extracts network components from coordinator
78+
└── Provides them to secondary services
79+
80+
Secondary Apps (Consensus, FileNode, Sync)
81+
├── Receive shared network via SharedNetworkManager
82+
├── Register their own RPC handlers to shared DRPC mux
83+
└── Service-specific components only
84+
```
85+
86+
**Benefits**:
87+
- Single port pair (33010 TCP, 33020 UDP) instead of 8 ports
88+
- Shared connection pool - all services reuse peer connections
89+
- Reduced memory usage - one network stack instead of four
90+
- True service bundling
91+
92+
**Implementation** (`lightnode/sharednetwork.go`):
93+
- `ExtractSharedNetwork(app)` - extracts network components from coordinator
94+
- `RegisterToApp(app)` - injects shared components into secondary services
95+
96+
**Startup Flow** (`cmd/start.go`):
97+
1. Create coordinator app (full network stack)
98+
2. Start coordinator
99+
3. Extract shared network via `ExtractSharedNetwork(coordinatorApp)`
100+
4. Create secondary apps with `sharedNet` parameter
101+
5. Start secondary apps (they reuse coordinator's network)
102+
103+
**Backward Compatibility**: Services can still run standalone by passing `nil` for `sharedNet` parameter.
60104

61105
### Key Components
62106

@@ -80,8 +124,17 @@ If coordinator doesn't start first, other services will fail to connect.
80124

81125
## Service Port Mapping
82126

83-
- TCP ports: 33010-33013 (various sync services)
84-
- UDP ports: 33020-33023 (QUIC transport)
127+
**New Shared Network Architecture** (default):
128+
- TCP port: 33010 (ALL services share ONE listener)
129+
- UDP port: 33020 (ALL services share ONE listener)
130+
131+
All services (coordinator, consensus, filenode, sync) register their RPC handlers to a single DRPC multiplexer:
132+
- Coordinator: `/CoordinatorService/*`
133+
- Consensus: `/ConsensusService/*`
134+
- FileNode: `/FileService/*`
135+
- SyncNode: `/SpaceSyncService/*`
136+
137+
These method namespaces don't conflict, so they coexist in one mux.
85138

86139
## Configuration Patterns
87140

cmd/start.go

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -77,16 +77,19 @@ func startAction(ctx context.Context) cli.ActionFunc {
7777
}
7878
}
7979

80-
// Initialize nodes. Coordinator MUST start first - others depend on it.
80+
// Create bundle with all services (coordinator, consensus, filenode, sync)
8181
cfgNodes := bundleCfg.NodeConfigs()
82+
bundle := lightnode.NewBundle(cfgNodes)
8283

84+
// Create node list for startup
8385
apps := []node{
84-
{name: "coordinator", app: lightnode.NewCoordinatorApp(cfgNodes.Coordinator)},
85-
{name: "consensus", app: lightnode.NewConsensusApp(cfgNodes.Consensus)},
86-
{name: "filenode", app: lightnode.NewFileNodeApp(cfgNodes.Filenode, cfgNodes.FilenodeStorePath)},
87-
{name: "sync", app: lightnode.NewSyncApp(cfgNodes.Sync)},
86+
{name: "coordinator", app: bundle.Coordinator},
87+
{name: "consensus", app: bundle.Consensus},
88+
{name: "filenode", app: bundle.FileNode},
89+
{name: "sync", app: bundle.Sync},
8890
}
8991

92+
// Start all services
9093
if err := startServices(ctx, apps); err != nil {
9194
return err
9295
}

config/bundle.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -163,22 +163,22 @@ func newBundleConfig(cfg *CreateOptions) *Config {
163163
},
164164
Consensus: NodeConsensus{
165165
NodeShared: NodeShared{
166-
ListenTCPAddr: "0.0.0.0:33011",
167-
ListenUDPAddr: "0.0.0.0:33021",
166+
ListenTCPAddr: "0.0.0.0:33010",
167+
ListenUDPAddr: "0.0.0.0:33020",
168168
},
169169
MongoConnect: mongoConsensusURI.String(),
170170
MongoDatabase: "consensus",
171171
},
172172
Tree: Tree{
173173
NodeShared{
174-
ListenTCPAddr: "0.0.0.0:33012",
175-
ListenUDPAddr: "0.0.0.0:33022",
174+
ListenTCPAddr: "0.0.0.0:33010",
175+
ListenUDPAddr: "0.0.0.0:33020",
176176
},
177177
},
178178
File: NodeFile{
179179
NodeShared: NodeShared{
180-
ListenTCPAddr: "0.0.0.0:33013",
181-
ListenUDPAddr: "0.0.0.0:33023",
180+
ListenTCPAddr: "0.0.0.0:33010",
181+
ListenUDPAddr: "0.0.0.0:33020",
182182
},
183183
RedisConnect: cfg.RedisURI,
184184
},

config/client.go

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -50,26 +50,8 @@ func (bc *Config) YamlClientConfig() ([]byte, error) {
5050
Addresses: bc.convertExternalAddrs(bc.Nodes.Coordinator.NodeShared),
5151
Types: []nodeconf.NodeType{
5252
nodeconf.NodeTypeCoordinator,
53-
},
54-
},
55-
{
56-
PeerId: bc.Accounts.Consensus.PeerId,
57-
Addresses: bc.convertExternalAddrs(bc.Nodes.Consensus.NodeShared),
58-
Types: []nodeconf.NodeType{
5953
nodeconf.NodeTypeConsensus,
60-
},
61-
},
62-
{
63-
PeerId: bc.Accounts.Tree.PeerId,
64-
Addresses: bc.convertExternalAddrs(bc.Nodes.Tree.NodeShared),
65-
Types: []nodeconf.NodeType{
6654
nodeconf.NodeTypeTree,
67-
},
68-
},
69-
{
70-
PeerId: bc.Accounts.File.PeerId,
71-
Addresses: bc.convertExternalAddrs(bc.Nodes.File.NodeShared),
72-
Types: []nodeconf.NodeType{
7355
nodeconf.NodeTypeFile,
7456
},
7557
},

config/convert.go

Lines changed: 6 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -196,22 +196,12 @@ func (bc *Config) networkCfg() nodeconf.Configuration {
196196
{
197197
PeerId: bc.Accounts.Coordinator.PeerId,
198198
Addresses: convertListenToConnect(bc.Nodes.Coordinator.NodeShared),
199-
Types: []nodeconf.NodeType{nodeconf.NodeTypeCoordinator},
200-
},
201-
{
202-
PeerId: bc.Accounts.Consensus.PeerId,
203-
Addresses: convertListenToConnect(bc.Nodes.Consensus.NodeShared),
204-
Types: []nodeconf.NodeType{nodeconf.NodeTypeConsensus},
205-
},
206-
{
207-
PeerId: bc.Accounts.Tree.PeerId,
208-
Addresses: convertListenToConnect(bc.Nodes.Tree.NodeShared),
209-
Types: []nodeconf.NodeType{nodeconf.NodeTypeTree},
210-
},
211-
{
212-
PeerId: bc.Accounts.File.PeerId,
213-
Addresses: convertListenToConnect(bc.Nodes.File.NodeShared),
214-
Types: []nodeconf.NodeType{nodeconf.NodeTypeFile},
199+
Types: []nodeconf.NodeType{
200+
nodeconf.NodeTypeCoordinator,
201+
nodeconf.NodeTypeConsensus,
202+
nodeconf.NodeTypeTree,
203+
nodeconf.NodeTypeFile,
204+
},
215205
},
216206
},
217207
CreationTime: time.Now(),

0 commit comments

Comments
 (0)