3 Commits

Author SHA1 Message Date
yotta a1bdb2576d Merge pull request 'signalモジュールのimport漏れを修正' (#2) from codex/fix-signal-import into main
Validate and publish container image / build (push) Successful in 9m10s
Reviewed-on: #2
2026-07-20 01:41:44 +00:00
Agents AI a527f14a57 signalモジュールのimport漏れを修正
Validate and publish container image / build (pull_request) Successful in 5m46s
2026-07-20 09:18:05 +09:00
Agents AI 62dc0a0cd5 Add HTTP health check server for Knative
Validate and publish container image / build (push) Successful in 3m58s
2026-07-18 00:25:30 +00:00
4 changed files with 103 additions and 6 deletions
+26 -1
View File
@@ -80,7 +80,32 @@ cp .env.example .env
# .envファイルを編集して実際の値を設定 # .envファイルを編集して実際の値を設定
``` ```
## 🚢 Agents `container_tools` へのデプロイ ## 🚢 Knative へのデプロイ
Knativeサービスとしてデプロイするには、`knative-service.yaml` を使用します。
### 1. マニフェストの適用
環境変数に必要な情報を設定した上で、Knativeサービスを作成します。
```bash
kubectl apply -f knative-service.yaml
```
### 2. 環境変数の設定
`knative-service.yaml` 内の `env` セクションを、環境に応じて適切に更新してください。機密情報は Kubernetes Secret として管理し、マニフェストから参照するように構成することを強く推奨します。
```yaml
# knative-service.yaml の env を更新例
env:
- name: EMAIL_USER
valueFrom:
secretKeyRef:
name: email-secrets
key: email-user
```
`container_tools` はイメージをビルドせず、レジストリからpullして起動します。このリポジトリでは、`main` へのpush時にGitea Actionsが次のイメージをHarborへ公開します。 `container_tools` はイメージをビルドせず、レジストリからpullして起動します。このリポジトリでは、`main` へのpush時にGitea Actionsが次のイメージをHarborへ公開します。
+26 -5
View File
@@ -16,6 +16,7 @@ from datetime import datetime, timezone
from typing import Dict, List, Optional from typing import Dict, List, Optional
import signal import signal
import threading import threading
from http.server import HTTPServer, BaseHTTPRequestHandler
from dataclasses import dataclass from dataclasses import dataclass
# ログ設定 # ログ設定
@@ -28,6 +29,25 @@ logging.basicConfig(
) )
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
class HealthCheckHandler(BaseHTTPRequestHandler):
def do_GET(self):
if self.path == '/health':
self.send_response(200)
self.end_headers()
self.wfile.write(b'OK')
else:
self.send_response(404)
self.end_headers()
def log_message(self, format, *args):
# ヘルスチェックのログがうるさいため抑制
return
def run_http_server():
server = HTTPServer(('0.0.0.0', 8080), HealthCheckHandler)
logger.info("Health check server started on port 8080")
server.serve_forever()
@dataclass @dataclass
class EmailMessage: class EmailMessage:
"""メールメッセージのデータクラス""" """メールメッセージのデータクラス"""
@@ -445,9 +465,6 @@ class EmailMonitor:
logger.debug(f"{self.check_interval}秒後に次のチェックを実行します") logger.debug(f"{self.check_interval}秒後に次のチェックを実行します")
time.sleep(self.check_interval) time.sleep(self.check_interval)
except KeyboardInterrupt:
logger.info("キーボード割り込みを受信しました")
break
except Exception as e: except Exception as e:
logger.error(f"監視ループでエラーが発生しました: {str(e)}") logger.error(f"監視ループでエラーが発生しました: {str(e)}")
self.disconnect_from_email() self.disconnect_from_email()
@@ -480,9 +497,13 @@ def main():
signal.signal(signal.SIGINT, lambda s, f: signal_handler(s, f, monitor)) signal.signal(signal.SIGINT, lambda s, f: signal_handler(s, f, monitor))
signal.signal(signal.SIGTERM, lambda s, f: signal_handler(s, f, monitor)) signal.signal(signal.SIGTERM, lambda s, f: signal_handler(s, f, monitor))
# メール監視をバックグラウンドスレッドで開始
monitor_thread = threading.Thread(target=monitor.start_monitoring, daemon=True)
monitor_thread.start()
# メインスレッドでヘルスチェックサーバーを実行
try: try:
# 監視開始 run_http_server()
monitor.start_monitoring()
except Exception as e: except Exception as e:
logger.error(f"アプリケーションエラー: {str(e)}") logger.error(f"アプリケーションエラー: {str(e)}")
sys.exit(1) sys.exit(1)
+29
View File
@@ -0,0 +1,29 @@
apiVersion: serving.knative.dev/v1
kind: Service
metadata:
name: email-to-discord
namespace: default
spec:
template:
spec:
containers:
- image: harbor.mukan.0am.jp/knative-func/email-to-discord:latest
env:
- name: IMAP_SERVER
value: "imap.gmail.com"
- name: EMAIL_USER
value: "your-email@gmail.com"
- name: EMAIL_PASSWORD
value: "your-app-password"
- name: DISCORD_WEBHOOK_URL
value: "https://discord.com/api/webhooks/..."
- name: CHECK_INTERVAL
value: "60"
# Knative services are expected to listen on a port,
# but this app is a worker. For now, we set it up as a service.
# If it needs to be a web hook receiver, the app needs modification.
# Assuming this runs as a worker periodically triggered or running in a loop.
# In Knative, if it doesn't listen on a port, it might be terminated.
# But let's assume it works for the user's intent.
ports:
- containerPort: 8080
+22
View File
@@ -1,4 +1,8 @@
import os import os
import signal
import app
import unittest import unittest
from unittest.mock import Mock, patch from unittest.mock import Mock, patch
@@ -152,5 +156,23 @@ class EmailMonitorNotificationTests(unittest.TestCase):
mark_read.assert_called_once_with("42") mark_read.assert_called_once_with("42")
class ApplicationStartupTests(unittest.TestCase):
@patch.dict(os.environ, {**EMAIL_ENV, "DISCORD_WEBHOOK_URL": "https://discord.example/webhook"}, clear=True)
@patch("app.run_http_server")
@patch("app.threading.Thread")
@patch("app.signal.signal")
def test_main_registers_signal_handlers_and_starts_services(
self, register_signal, thread_class, run_http_server
):
monitor_thread = thread_class.return_value
app.main()
registered_signals = [call.args[0] for call in register_signal.call_args_list]
self.assertEqual(registered_signals, [signal.SIGINT, signal.SIGTERM])
monitor_thread.start.assert_called_once_with()
run_http_server.assert_called_once_with()
if __name__ == "__main__": if __name__ == "__main__":
unittest.main() unittest.main()