Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 41 additions & 9 deletions tools/collect_hbnj_all.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import argparse
import re
import sys
import time
from datetime import datetime, timezone
from pathlib import Path
Expand All @@ -15,11 +16,27 @@ def main() -> int:
parser.add_argument("--date", required=True, help="Broadcast date in YYYYMMDD form")
parser.add_argument("--out", type=Path, required=True)
parser.add_argument("--delay", type=float, default=0.5, help="Delay between region requests")
parser.add_argument(
"--retries",
type=int,
default=3,
help="Attempts per region before failing the complete build",
)
parser.add_argument(
"--retry-delay",
type=float,
default=1.0,
help="Initial retry delay in seconds (doubles after each failure)",
)
args = parser.parse_args()
if not re.fullmatch(r"\d{8}", args.date):
raise SystemExit("--date must use YYYYMMDD")
if args.delay < 0:
raise SystemExit("--delay cannot be negative")
if args.retries < 1:
raise SystemExit("--retries must be at least 1")
if args.retry_delay < 0:
raise SystemExit("--retry-delay cannot be negative")

areas: list[dict[str, object]] = []
channels: list[dict[str, object]] = []
Expand All @@ -34,15 +51,30 @@ def main() -> int:
f"group={group_id} area={area_name}",
flush=True,
)
source_url, source = fetch(group_id, args.date)
region = parse_region(
source,
group_id=group_id,
area_id=area_id,
area_name=area_name,
prefecture_raw=prefecture_raw,
source_url=source_url,
)
for attempt in range(1, args.retries + 1):
try:
source_url, source = fetch(group_id, args.date)
region = parse_region(
source,
group_id=group_id,
area_id=area_id,
area_name=area_name,
prefecture_raw=prefecture_raw,
source_url=source_url,
)
break
except Exception as error:
if attempt == args.retries:
raise
wait = args.retry_delay * (2 ** (attempt - 1))
print(
f" attempt {attempt}/{args.retries} failed: "
f"{type(error).__name__}: {error}; retrying in {wait:g}s",
file=sys.stderr,
flush=True,
)
if wait:
time.sleep(wait)
area = dict(region["area"])
areas.append(area)
channels.extend(region["channels"])
Expand Down
11 changes: 9 additions & 2 deletions tools/run_hbnj_daily.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,16 @@ $log = Join-Path $logDirectory "hbnj-update-$stamp.log"
Push-Location $workspace
try {
$env:PYTHONIOENCODING = "utf-8"
# Windows PowerShell promotes native stderr to an ErrorRecord. This Python
# installation emits a harmless prefix warning on stderr, so temporarily
# allow the process to finish and judge success by its actual exit code.
$previousErrorActionPreference = $ErrorActionPreference
$ErrorActionPreference = "Continue"
& py -3 "tools\update_hbnj_daily.py" *>&1 | Tee-Object -FilePath $log
if ($LASTEXITCODE -ne 0) {
throw "HBNJ updater exited with code $LASTEXITCODE"
$updaterExitCode = $LASTEXITCODE
$ErrorActionPreference = $previousErrorActionPreference
if ($updaterExitCode -ne 0) {
Comment on lines +14 to +19

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: ErrorActionPreference is restored only in the success path of capturing $updaterExitCode; consider guarding restoration with try/finally inside the inner block.

If an error occurs between changing $ErrorActionPreference and setting $updaterExitCode (e.g., a terminating error in the pipeline), the script will abort while still using the modified preference. Enclosing the py call and $LASTEXITCODE assignment in try { ... } finally { $ErrorActionPreference = $previousErrorActionPreference } ensures the original preference is always restored, even when that inner logic fails.

throw "HBNJ updater exited with code $updaterExitCode"
}
}
finally {
Expand Down
14 changes: 11 additions & 3 deletions tools/update_hbnj_daily.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@
import subprocess
import sys
import tempfile
from datetime import datetime
from datetime import datetime, timedelta, timezone
from pathlib import Path
from zoneinfo import ZoneInfo


WORKSPACE = Path(__file__).resolve().parents[1]
PRIVATE = WORKSPACE / "channels" / "hbnj" / "private"
CURRENT = WORKSPACE / "channels" / "hbnj" / "generated" / "current"
JAPAN_STANDARD_TIME = timezone(timedelta(hours=9), name="JST")


def run(*arguments: str) -> None:
Expand Down Expand Up @@ -56,8 +56,12 @@ def main() -> int:
help="Broadcast date in YYYYMMDD form (default: current date in Japan)",
)
parser.add_argument("--delay", type=float, default=0.5)
parser.add_argument("--retries", type=int, default=3)
parser.add_argument("--retry-delay", type=float, default=1.0)
args = parser.parse_args()
broadcast_date = args.date or datetime.now(ZoneInfo("Asia/Tokyo")).strftime("%Y%m%d")
# Japan has observed UTC+09:00 year-round since 1951, so this avoids an
# unnecessary dependency on the optional Windows IANA/tzdata package.
broadcast_date = args.date or datetime.now(JAPAN_STANDARD_TIME).strftime("%Y%m%d")
if len(broadcast_date) != 8 or not broadcast_date.isdigit():
raise SystemExit("--date must use YYYYMMDD")

Expand All @@ -74,6 +78,10 @@ def main() -> int:
str(guide),
"--delay",
str(args.delay),
"--retries",
str(args.retries),
"--retry-delay",
str(args.retry_delay),
)
run("tools/validate_hbnj_guide.py", str(guide))
run("tools/pack_hbnj_guide.py", str(guide), "--out-dir", str(payloads))
Expand Down
Loading