-
Notifications
You must be signed in to change notification settings - Fork 10
Expand file tree
/
Copy pathtrending_service.py
More file actions
182 lines (153 loc) · 5.61 KB
/
Copy pathtrending_service.py
File metadata and controls
182 lines (153 loc) · 5.61 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
#!/usr/bin/env python3
"""Main entry point for the GitHub Trending ingestion service.
This script provides a command-line interface for running the trending repository
ingestion engine. It supports both scheduled (daemon) mode and one-time execution.
Usage:
# Run as a scheduled service (refreshes every 24 hours)
uv run python trending_service.py --scheduled
# Run a single refresh cycle
uv run python trending_service.py --once
# Run with custom configuration
uv run python trending_service.py --once --limit 50 --refresh-hours 12
"""
import argparse
import logging
import os
import sys
# Load environment variables from .env file before importing config
try:
from dotenv import load_dotenv
load_dotenv()
except ImportError:
pass # python-dotenv is optional, continue without it
from trending.scheduler import run_scheduler, run_once
from trending.config import validate_config, TRENDING_REPO_LIMIT_STR, TRENDING_REFRESH_HOURS_STR
from trending.logger import setup_logger
def parse_args(argv: list[str] | None = None):
"""Parse command-line arguments."""
parser = argparse.ArgumentParser(
description="GitHub Trending Repository Ingestion Service",
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog="""
Examples:
%(prog)s --scheduled Run as a scheduled service (24-hour refresh cycle)
%(prog)s --once Run a single refresh cycle
%(prog)s --once --limit 50 Fetch 50 repositories instead of default 30
""",
)
mode_group = parser.add_mutually_exclusive_group(required=False)
mode_group.add_argument(
"--scheduled",
action="store_true",
help="Run as a scheduled service (refreshes every TRENDING_REFRESH_HOURS)",
)
mode_group.add_argument(
"--once",
action="store_true",
help="Run a single refresh cycle and exit",
)
parser.add_argument(
"--limit",
type=int,
default=None,
help=f"Number of repositories to fetch (default: {TRENDING_REPO_LIMIT_STR})",
)
parser.add_argument(
"--refresh-hours",
type=int,
default=None,
help=f"Refresh interval in hours (default: {TRENDING_REFRESH_HOURS_STR})",
)
parser.add_argument(
"--log-level",
type=str,
default="INFO",
choices=["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"],
help="Log level (default: INFO)",
)
parser.add_argument(
"--log-file",
type=str,
default=None,
help="Path to log file (default: stdout)",
)
parser.add_argument(
"--validate-config",
action="store_true",
help="Validate configuration and exit without running",
)
return parser.parse_args(argv)
def main(argv: list[str] | None = None):
"""Main entry point for the trending service."""
args = parse_args(argv)
# Setup logging
logger = setup_logger(
name="trending_service",
level=args.log_level,
log_file=args.log_file,
)
logger.info("GitHub Trending Ingestion Service")
logger.info("=" * 60)
# Override configuration if command-line arguments provided (before validation)
if args.limit is not None:
import trending.config as config
config.TRENDING_REPO_LIMIT_STR = str(args.limit)
logger.info(f"Override: TRENDING_REPO_LIMIT = {args.limit}")
if args.refresh_hours is not None:
import trending.config as config
config.TRENDING_REFRESH_HOURS_STR = str(args.refresh_hours)
logger.info(f"Override: TRENDING_REFRESH_HOURS = {args.refresh_hours}")
# Validate configuration (after CLI overrides)
config_errors = validate_config()
if config_errors:
logger.error("Configuration validation failed:")
for error in config_errors:
logger.error(f" - {error}")
sys.exit(1)
if args.validate_config:
missing = [
name for name in ("GITHUB_TOKEN", "BACKEND_URL", "INTERNAL_API_SECRET")
if not os.getenv(name)
]
if missing:
for name in missing:
logger.error(" - %s is required", name)
sys.exit(1)
logger.info("Configuration validation passed.")
sys.exit(0)
# Check if mode is specified
if not args.scheduled and not args.once:
logger.error("Either --scheduled or --once must be specified (unless using --validate-config)")
sys.exit(1)
# Run in requested mode
try:
from acquisition.backend_client import BackendIngestionClient
from trending.backend_storage import BackendTrendingStorage
backend = BackendIngestionClient(
base_url=os.environ["BACKEND_URL"],
internal_secret=os.environ["INTERNAL_API_SECRET"],
)
storage = BackendTrendingStorage(
backend=backend,
github_token=os.environ["GITHUB_TOKEN"],
)
if args.scheduled:
logger.info("Starting scheduled mode...")
run_scheduler(storage=storage)
elif args.once:
logger.info("Starting single refresh cycle...")
success = run_once(force=True, storage=storage)
if success:
logger.info("Single refresh cycle completed successfully.")
sys.exit(0)
else:
logger.error("Single refresh cycle failed.")
sys.exit(1)
except KeyboardInterrupt:
logger.info("Interrupted by user.")
sys.exit(0)
except Exception as exc:
logger.error(f"Fatal error: {exc}", exc_info=True)
sys.exit(1)
if __name__ == "__main__":
main()