diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..828d046 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,9 @@ +.git +**/__pycache__ +**/*.pyc +*.md +desktop-client +test-data +artifacts +kind-config.yaml +.github diff --git a/Dockerfile.orchestrator b/Dockerfile.orchestrator index 4d508d0..931de0e 100644 --- a/Dockerfile.orchestrator +++ b/Dockerfile.orchestrator @@ -9,6 +9,10 @@ RUN pip install --no-cache-dir -r requirements.txt # Copy orchestrator code COPY orchestrator/ ./orchestrator/ +# orchestrator/quality.py imports benchmark.fixtures / benchmark.metrics at startup, +# so the package must be present in the image (agent_swarm#44). stdlib-only — no extra pip. +COPY benchmark/ ./benchmark/ + # Expose port EXPOSE 8000 diff --git a/orchestrator/redis_client.py b/orchestrator/redis_client.py index 7df6782..1987e08 100644 --- a/orchestrator/redis_client.py +++ b/orchestrator/redis_client.py @@ -172,7 +172,16 @@ class RedisClient: await self.client.hdel(name, *keys) async def keys(self, pattern: str) -> list: - """Get keys matching pattern.""" + """Get keys matching pattern. + + In cluster mode KEYS must fan out to every primary and merge — the default + routing hits a single node, so on a multi-shard cluster it silently drops + keys living on other shards (breaks agent/task enumeration). redis-py merges + the per-node results into one flat list. + """ + if self.cluster: + from redis.asyncio.cluster import RedisCluster + return await self.client.keys(pattern, target_nodes=RedisCluster.PRIMARIES) return await self.client.keys(pattern) async def lpush(self, key: str, *values: str):