Skip to content

Commit 72bc9eb

Browse files
Copilotnotfolder
andauthored
Add continuous mode for docker-compose producer and consumer (#61)
* Initial plan * Add continuous mode for docker-compose producer and consumer Co-authored-by: notfolder <20558197+notfolder@users.noreply.github.com> * Fix code review comments: use relative path in test and improve log message Co-authored-by: notfolder <20558197+notfolder@users.noreply.github.com> * continus mode動作確認済み --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: notfolder <20558197+notfolder@users.noreply.github.com> Co-authored-by: notfolder <notfolder@gmail.com>
1 parent 96f34f2 commit 72bc9eb

10 files changed

Lines changed: 922 additions & 52 deletions

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ planning_history/*.jsonl
77
*.pyc
88
*.log
99
*.log.*
10+
*.health
1011
github-mcp-server.cmd
1112
__pycache__/
1213
.pytest_cache/

CONTINUOUS_MODE_SPECIFICATION.md

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -95,15 +95,15 @@ main.pyに`--continuous`オプションを追加します。
9595

9696
**設定方法:**
9797
- 設定ファイル: `continuous.producer.interval_minutes`
98-
- デフォルト値: 5分
98+
- デフォルト値: 1分
9999

100100
**設定例:**
101101
```yaml
102102
# config.yamlへの追加
103103
continuous:
104104
producer:
105105
# タスク取得間隔(分)
106-
interval_minutes: 5
106+
interval_minutes: 1
107107
```
108108
109109
#### 3.2.3 待機処理の実装方針
@@ -230,7 +230,7 @@ continuous:
230230
231231
producer:
232232
# タスク取得間隔(分)
233-
interval_minutes: 5
233+
interval_minutes: 1
234234
235235
# 起動時の初回実行を遅延させるか(デフォルト: false)
236236
# trueの場合、起動直後にinterval_minutes待機してから最初のタスク取得を行う
@@ -332,7 +332,7 @@ services:
332332
# - 短時間タスクが多い場合: 60s〜120s に短縮可能
333333
# - 長時間タスクがある場合: 600s 以上に延長を推奨
334334
# max_llm_process_numの設定値と平均処理時間を考慮して調整してください。
335-
stop_grace_period: 300s
335+
stop_grace_period: 600s
336336
```
337337

338338
#### 3.6.2 Consumerのスケールアウト
@@ -373,7 +373,7 @@ services:
373373
# ... 他の設定 ...
374374
healthcheck:
375375
test: ["CMD", "python", "-c", "import os, time; f='/app/healthcheck/producer.health'; exit(0 if os.path.exists(f) and time.time() - os.path.getmtime(f) < 600 else 1)"]
376-
interval: 60s
376+
interval: 300s
377377
timeout: 10s
378378
retries: 3
379379
start_period: 30s
@@ -418,14 +418,14 @@ services:
418418
**起動時:**
419419
```
420420
INFO - 継続動作モードで起動しました(Producer)
421-
INFO - タスク取得間隔: 5分
421+
INFO - タスク取得間隔: 1分
422422
```
423423
424424
**ループ実行時:**
425425
```
426426
INFO - タスク取得処理を開始します(ループ回数: 10)
427427
INFO - 3件のタスクをキューに追加しました
428-
INFO - 次のタスク取得まで5分待機します
428+
INFO - 次のタスク取得まで1分待機します
429429
```
430430
431431
**シャットダウン時:**

Dockerfile

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,14 +35,17 @@ WORKDIR /app
3535
# コードコピー
3636
COPY . /app
3737

38-
# Node.js, npm, npxインストール
38+
# Node.js, npm, gitインストール
3939
RUN apt-get update && \
40-
apt-get install -y nodejs npm git && \
41-
npm install -g npx
40+
apt-get install -y nodejs npm git
4241

43-
RUN npm install @zereight/mcp-gitlab@latest
42+
# グローバルにmcp-gitlabをインストール
43+
RUN npm install -g @zereight/mcp-gitlab@latest
44+
45+
# npxもグローバルにインストール(既存の場合は上書き)
46+
RUN npm install -g npx --force
4447

4548
COPY --from=build /bin/github-mcp-server ./github-mcp-server.cmd
4649

47-
# npxで@zereight/mcp-gitlabを起動し、main.pyも起動
48-
ENTRYPOINT ["stdbuf", "-oL", "conda", "run", "-n", "coding-agent", "python", "-u", "main.py"]
50+
# conda環境でPythonスクリプトを実行するためのエントリーポイント
51+
ENTRYPOINT ["conda", "run", "-n", "coding-agent", "--no-capture-output"]

clients/mcp_tool_client.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import asyncio
44
import hashlib
55
import json
6+
import logging
67
import os
78
import threading
89
from typing import TYPE_CHECKING, Any
@@ -58,9 +59,16 @@ def _run_async(self, coro: Awaitable[object]) -> object:
5859

5960
def _run_with_session(self, coro_fn: Callable[[ClientSession], Awaitable[object]]) -> object:
6061
async def wrapper() -> object:
62+
logger = logging.getLogger(__name__)
63+
server_name = self.server_config.get("mcp_server_name", "unknown")
6164
cmd = self.server_config["command"][0]
6265
args = self.server_config["command"][1:]
6366
env = self.server_config.get("env", {})
67+
68+
logger.debug("Starting MCP server: %s", server_name)
69+
logger.debug(" Command: %s %s", cmd, " ".join(args))
70+
logger.debug(" Env keys: %s", list(env.keys()))
71+
6472
merged_env = dict(os.environ)
6573
merged_env.update(env)
6674
server_params = StdioServerParameters(command=cmd, args=args, env=merged_env)
@@ -74,6 +82,7 @@ async def wrapper() -> object:
7482
InitializedNotification(method="notifications/initialized"),
7583
)
7684
await session.send_notification(notification)
85+
logger.debug("MCP server initialized: %s", server_name)
7786
return await coro_fn(session)
7887

7988
return self._run_async(wrapper())

condaenv.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,5 @@ dependencies:
2121
- lmstudio
2222
- openai
2323
- ollama
24+
- portalocker
2425
# - hashing-mcp-server

config.yaml

Lines changed: 43 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,18 +11,21 @@ mcp_servers:
1111
- "npx"
1212
- "@zereight/mcp-gitlab"
1313
- "stdio"
14+
env:
15+
GITLAB_PERSONAL_ACCESS_TOKEN: ""
16+
GITLAB_API_URL: ""
1417

15-
- mcp_server_name: "googlesearch"
16-
command:
17-
- "npx"
18-
- "-y"
19-
- "@adenot/mcp-google-search"
18+
# - mcp_server_name: "googlesearch"
19+
# command:
20+
# - "npx"
21+
# - "-y"
22+
# - "@adenot/mcp-google-search"
2023

21-
- mcp_server_name: "webfetch"
22-
command:
23-
- "python"
24-
- "-m"
25-
- "mcp_server_fetch"
24+
# - mcp_server_name: "webfetch"
25+
# command:
26+
# - "python"
27+
# - "-m"
28+
# - "mcp_server_fetch"
2629

2730
# APIサーバー設定
2831
api_server:
@@ -199,3 +202,33 @@ rabbitmq:
199202
user: guest
200203
password: guest
201204
queue: coding_agent_tasks
205+
206+
# 継続動作モードの設定
207+
# docker-composeでproducerとconsumerを継続的に動作させる場合に使用
208+
continuous:
209+
# 継続動作モードの有効化(デフォルト: false)
210+
# 注: この設定よりコマンドラインオプション --continuous が優先される
211+
enabled: false
212+
213+
producer:
214+
# タスク取得間隔(分)
215+
interval_minutes: 1
216+
217+
# 起動時の初回実行を遅延させるか(デフォルト: false)
218+
# trueの場合、起動直後にinterval_minutes待機してから最初のタスク取得を行う
219+
delay_first_run: false
220+
221+
consumer:
222+
# キュー取得タイムアウト(秒)
223+
queue_timeout_seconds: 30
224+
225+
# タスク処理間の最小待機時間(秒、デフォルト: 0)
226+
# レート制限などが必要な場合に設定
227+
min_interval_seconds: 0
228+
229+
# ヘルスチェック設定
230+
healthcheck:
231+
# ヘルスチェックディレクトリ
232+
dir: "healthcheck"
233+
# ヘルスチェック更新間隔(秒)
234+
update_interval_seconds: 60

docker-compose.yml

Lines changed: 113 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,15 @@ services:
33
user-config-api:
44
build: ./user_config_api
55
container_name: user-config-api
6-
# Docker内部ネットワークのみで使用外部公開不要
6+
# Docker内部ネットワークのみで使用(外部公開不要)
77
# テスト用に外部アクセスが必要な場合のみ、以下のコメントを外す
88
ports:
99
- "8081:8080"
1010
environment:
1111
API_SERVER_KEY: ${API_SERVER_KEY:-your-secret-api-key-here}
1212

1313
web:
14-
image: 'gitlab/gitlab-ce:latest'
14+
image: 'gitlab/gitlab-ce:18.5.3-ce.0'
1515
restart: always
1616
ports:
1717
- '8080:80'
@@ -22,6 +22,12 @@ services:
2222
- './gitlab/logs:/var/log/gitlab'
2323
- './gitlab/data:/var/opt/gitlab'
2424
shm_size: '256m'
25+
healthcheck:
26+
test: ["CMD-SHELL", "curl -f http://localhost/-/health || exit 1"]
27+
interval: 30s
28+
timeout: 10s
29+
retries: 10
30+
start_period: 120s
2531

2632
rabbitmq:
2733
image: rabbitmq:3-management
@@ -35,5 +41,110 @@ services:
3541
volumes:
3642
- rabbitmq_data:/var/lib/rabbitmq
3743

44+
# Producer サービス - タスクを継続的に取得してキューに追加
45+
coding-agent-producer:
46+
build: .
47+
container_name: coding-agent-producer
48+
command: ["python", "main.py", "--mode", "producer", "--continuous"]
49+
depends_on:
50+
rabbitmq:
51+
condition: service_started
52+
user-config-api:
53+
condition: service_started
54+
web:
55+
condition: service_healthy
56+
environment:
57+
# 必須環境変数
58+
- TASK_SOURCE=${TASK_SOURCE:-github}
59+
- GITHUB_PERSONAL_ACCESS_TOKEN=${GITHUB_PERSONAL_ACCESS_TOKEN}
60+
- GITLAB_PERSONAL_ACCESS_TOKEN=${GITLAB_PERSONAL_ACCESS_TOKEN:-}
61+
- GITLAB_API_URL=${GITLAB_API_URL:-https://gitlab.com/api/v4}
62+
- GITLAB_BOT_NAME=${GITLAB_BOT_NAME:-bot}
63+
- GITHUB_BOT_NAME=${GITHUB_BOT_NAME:-bot}
64+
65+
# RabbitMQ設定
66+
- RABBITMQ_HOST=rabbitmq
67+
- RABBITMQ_PORT=5672
68+
- RABBITMQ_USER=guest
69+
- RABBITMQ_PASSWORD=guest
70+
71+
# LLM設定
72+
- LLM_PROVIDER=${LLM_PROVIDER:-openai}
73+
- OPENAI_API_KEY=${OPENAI_API_KEY:-}
74+
- OPENAI_BASE_URL=${OPENAI_BASE_URL:-https://api.openai.com/v1}
75+
- OPENAI_MODEL=${OPENAI_MODEL:-gpt-4o}
76+
77+
# ログ設定
78+
- LOGS=/app/logs/producer.log
79+
- DEBUG=${DEBUG:-false}
80+
volumes:
81+
- ./logs:/app/logs
82+
- ./contexts:/app/contexts
83+
- ./healthcheck:/app/healthcheck
84+
restart: unless-stopped
85+
# gracefulシャットダウンの猶予時間
86+
stop_grace_period: 300s
87+
healthcheck:
88+
test: ["CMD", "python", "-c", "import os, time; f='/app/healthcheck/producer.health'; exit(0 if os.path.exists(f) and time.time() - os.path.getmtime(f) < 600 else 1)"]
89+
interval: 300s
90+
timeout: 10s
91+
retries: 3
92+
start_period: 30s
93+
94+
# Consumer サービス - キューからタスクを継続的に取得して処理
95+
coding-agent-consumer:
96+
build: .
97+
container_name: coding-agent-consumer
98+
command: ["python", "main.py", "--mode", "consumer", "--continuous"]
99+
depends_on:
100+
rabbitmq:
101+
condition: service_started
102+
user-config-api:
103+
condition: service_started
104+
web:
105+
condition: service_healthy
106+
environment:
107+
# 必須環境変数
108+
- TASK_SOURCE=${TASK_SOURCE:-github}
109+
- GITHUB_PERSONAL_ACCESS_TOKEN=${GITHUB_PERSONAL_ACCESS_TOKEN}
110+
- GITLAB_PERSONAL_ACCESS_TOKEN=${GITLAB_PERSONAL_ACCESS_TOKEN:-}
111+
- GITLAB_API_URL=${GITLAB_API_URL:-https://gitlab.com/api/v4}
112+
- GITLAB_BOT_NAME=${GITLAB_BOT_NAME:-bot}
113+
- GITHUB_BOT_NAME=${GITHUB_BOT_NAME:-bot}
114+
115+
# RabbitMQ設定
116+
- RABBITMQ_HOST=rabbitmq
117+
- RABBITMQ_PORT=5672
118+
- RABBITMQ_USER=guest
119+
- RABBITMQ_PASSWORD=guest
120+
121+
# LLM設定
122+
- LLM_PROVIDER=${LLM_PROVIDER:-openai}
123+
- OPENAI_API_KEY=${OPENAI_API_KEY:-}
124+
- OPENAI_BASE_URL=${OPENAI_BASE_URL:-https://api.openai.com/v1}
125+
- OPENAI_MODEL=${OPENAI_MODEL:-gpt-4o}
126+
127+
# ログ設定
128+
- LOGS=/app/logs/consumer.log
129+
- DEBUG=${DEBUG:-false}
130+
volumes:
131+
- ./logs:/app/logs
132+
- ./contexts:/app/contexts
133+
- ./healthcheck:/app/healthcheck
134+
restart: unless-stopped
135+
# gracefulシャットダウンの猶予時間(タスク処理完了を待つ)
136+
# 注: タスク処理に時間がかかる場合(LLM呼び出し、ファイル操作等)、
137+
# 処理中のタスクを完了させるために十分な時間を確保する必要があります。
138+
# デフォルト: 300秒(5分)
139+
# - 短時間タスクが多い場合: 60s〜120s に短縮可能
140+
# max_llm_process_numの設定値と平均処理時間を考慮して調整してください。
141+
stop_grace_period: 300s
142+
healthcheck:
143+
test: ["CMD", "python", "-c", "import os, time; f='/app/healthcheck/consumer.health'; exit(0 if os.path.exists(f) and time.time() - os.path.getmtime(f) < 600 else 1)"]
144+
interval: 300s
145+
timeout: 10s
146+
retries: 3
147+
start_period: 30s
148+
38149
volumes:
39150
rabbitmq_data:

0 commit comments

Comments
 (0)