You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
DELETE /actor-ts/cluster/shards/{typeName}/placements/{shardId}
→ removes the explicit placement; shard reverts to fallback strategy on next rebalance.
3. Manual rebalance API.
POST /actor-ts/cluster/shards/{typeName}/rebalance
Body: { "shardIds": [42, 43, 44] }
Forces the coordinator to re-evaluate those shards (HandOff + Allocate). With an external placement set, this is how operators move shards "right now" without waiting for the next rebalance tick.
4. Programmatic API.
exportclassExternalAllocationController{constructor(privatereadonlycluster: Cluster,privatereadonlytypeName: string);/** Set or update an explicit placement. Persists + gossips. */asyncsetPlacement(shardId: number,target: NodeAddress): Promise<void>;/** Remove an explicit placement. Shard reverts to fallback on next rebalance. */asyncremovePlacement(shardId: number): Promise<void>;/** Get current explicit placements. */asyncgetPlacements(): Promise<ReadonlyMap<number,NodeAddress>>;/** Force re-evaluation of these shards (HandOff + Allocate). */asyncrebalanceNow(shardIds: ReadonlyArray<number>): Promise<void>;}
Integration with existing actor-ts subsystems
ShardCoordinator: holds the explicitPlacements map; gossips changes to other regions; consulted on every allocation decision.
AllocationStrategy: new externalAllocationStrategy() factory; existing strategies (HashAllocationStrategy, LeastShardAllocationStrategy) are unchanged.
Gossip: ShardingProtocol.PlacementUpdate message added; piggy-backs on existing sharding gossip.
Out of scope / non-goals
Cross-cluster placement (move a shard to a different cluster): out of scope; that's a cluster-mesh concern, not external allocation.
Latency-aware automatic placement: out of scope; the framework provides the hook + the API, not the latency-measurement logic.
Capacity-aware automatic placement: same — providing the hook, not the measurement.
Persistent external state across coordinator restart: phase 1 keeps placements in coordinator memory + gossip; if every region restarts simultaneously, placements are lost. Phase 2 (separate ticket) could persist to the journal.
Open design questions
What if the target node is unreachable? External placement says "shard 42 → node B"; node B is unreachable. Options:
Block the shard (don't allocate anywhere) until B recovers.
Fall back to default strategy (current sketch).
Mark the placement as "pending" and allocate elsewhere temporarily.
Recommend: fall back + warn; explicit placement is a preference, not a constraint.
REST API auth: management endpoints currently rely on user-supplied middleware. Document the requirement.
State propagation latency: how fast does a setPlacement from operator's REST call propagate to all regions? Currently sharding gossip is ~1s. For canary scenarios this is fine; for emergency evacuation, faster.
Conflict resolution: two operators set conflicting placements for the same shard. Last-write-wins (timestamp-based) vs. coordinator-as-tie-breaker. LWW is simpler.
Test plan
Explicit placement honored — setPlacement(42, nodeB) then trigger allocation; shard 42 lands on B.
Fallback strategy on missing placement — shards without explicit placement use the fallback (e.g. LeastShard).
Removed placement — removePlacement(42); next rebalance moves shard 42 according to fallback.
Size / Priority
Rationale
Built-in
AllocationStrategyimpls cover ~80% of needs:HashAllocationStrategy(deterministic byshardId % N).LeastShardAllocationStrategy(load-balance by current count).Production users sometimes need to influence shard placement based on signals outside the sharding subsystem's view:
Today these require sub-classing
AllocationStrategyand recompiling. The framework should expose:POST /actor-ts/cluster/shards/rebalance { shards: [{id, target}] }— operator initiates explicit moves.Reference: what Akka does
The default strategy is the fallback; the external strategy overrides for shards that have been explicitly placed.
Design sketch — actor-ts equivalent
1. New
AllocationStrategy.external()factory.Behaviour:
allocate(shardId, candidates):explicitPlacements.has(shardId): verify the target is incandidates; if so, return it. Otherwise fall through tofallback.fallback.rebalance(currentShards, candidates, rebalanceInProgress):explicitPlacements.2. REST endpoint for operator-initiated placement.
Persists to a small per-type allocation state in the coordinator. State is gossiped along with normal sharding state.
3. Manual rebalance API.
Forces the coordinator to re-evaluate those shards (HandOff + Allocate). With an external placement set, this is how operators move shards "right now" without waiting for the next rebalance tick.
4. Programmatic API.
Integration with existing actor-ts subsystems
ShardCoordinator: holds theexplicitPlacementsmap; gossips changes to other regions; consulted on every allocation decision.AllocationStrategy: newexternalAllocationStrategy()factory; existing strategies (HashAllocationStrategy,LeastShardAllocationStrategy) are unchanged.ShardingProtocol.PlacementUpdatemessage added; piggy-backs on existing sharding gossip.Out of scope / non-goals
Open design questions
Recommend: fall back + warn; explicit placement is a preference, not a constraint.
setPlacementfrom operator's REST call propagate to all regions? Currently sharding gossip is ~1s. For canary scenarios this is fine; for emergency evacuation, faster.Test plan
setPlacement(42, nodeB)then trigger allocation; shard 42 lands on B.removePlacement(42); next rebalance moves shard 42 according to fallback.setPlacement(42, nodeB); nodeB unreachable; shard allocated via fallback + warning logged.rebalanceNow([42]); coordinator emits HandOff + Allocate for shard 42 within one tick.POST /actor-ts/cluster/shards/Counter/placementsbody parsed correctly + persists.setPlacementon region A reaches region B within one gossip interval.Acceptance criteria
externalAllocationStrategy(fallback, getState)factory exported.ExternalAllocationControllerclass exported.POST/GET/DELETE /actor-ts/cluster/shards/{typeName}/placements+POST .../rebalance.ShardCoordinatorgossips placement changes.