krz/hutch-stats

Server-side utility for calculating contributions for sourcehut users.

clone: git clone https://gitbay.org/krz/hutch-stats.git

fe5efeb33639e963029c3a118ccc2e98bafccb58

verified · cmc

author: Christian Cleberg <hello@cleberg.net> · 2026-04-12T01:45:27Z

feat: make sync overlap configurable, reduce default from 24h to 1h
 src/srht_contrib/config.py      |  3 +++
 src/srht_contrib/jobs/poller.py | 12 +++++++++---
 src/srht_contrib/main.py        |  2 +-
 3 files changed, 13 insertions(+), 4 deletions(-)

diff --git a/src/srht_contrib/config.py b/src/srht_contrib/config.py
index 56da6ff..80884c1 100644
--- a/src/srht_contrib/config.py
+++ b/src/srht_contrib/config.py
@@ -35,6 +35,9 @@ class Settings(BaseSettings):
     )
     default_actor: str = Field(default="~unknown", alias="DEFAULT_ACTOR")
     poll_interval_seconds: int = Field(default=900, alias="POLL_INTERVAL_SECONDS")
+    sync_overlap_hours: int = Field(default=1, alias="SYNC_OVERLAP_HOURS")
+    srht_request_delay_seconds: float = Field(default=0.5, alias="SRHT_REQUEST_DELAY_SECONDS")
+    git_repo_discovery_ttl_seconds: int = Field(default=3600, alias="GIT_REPO_DISCOVERY_TTL_SECONDS")
     actor_aliases_json: dict[str, list[str]] = Field(
         default_factory=dict,
         alias="ACTOR_ALIASES_JSON",
diff --git a/src/srht_contrib/jobs/poller.py b/src/srht_contrib/jobs/poller.py
index ff0aaae..94a7d96 100644
--- a/src/srht_contrib/jobs/poller.py
+++ b/src/srht_contrib/jobs/poller.py
@@ -8,6 +8,7 @@ from sqlalchemy import select
 from sqlalchemy.exc import IntegrityError
 from sqlalchemy.orm import Session
 
+from srht_contrib.config import Settings
 from srht_contrib.models import ContributionEvent, ServiceBackfillState, SyncState, TrackedActor, TrackedRepository
 from srht_contrib.schemas import NormalizedEvent
 from srht_contrib.services.git import GitIngestionService
@@ -18,14 +19,19 @@ from srht_contrib.utils.repositories import canonicalize_repository_name
 
 
 logger = logging.getLogger(__name__)
-SYNC_OVERLAP = timedelta(hours=24)
 RECENT_BACKFILL_BATCHES_PER_SERVICE = 5
 
 
 class PollerService:
-    def __init__(self, todo_service: TodoIngestionService, git_service: GitIngestionService) -> None:
+    def __init__(
+        self,
+        todo_service: TodoIngestionService,
+        git_service: GitIngestionService,
+        settings: Settings,
+    ) -> None:
         self.todo_service = todo_service
         self.git_service = git_service
+        self._sync_overlap = timedelta(hours=settings.sync_overlap_hours)
 
     def poll_all(self, db: Session, actor: str) -> int:
         self.track_actor_request(db, actor, update_last_requested=False)
@@ -104,7 +110,7 @@ class PollerService:
         )
         since = datetime.now(tz=UTC) - timedelta(days=30)
         if state and state.cursor_value:
-            since = datetime.fromisoformat(state.cursor_value.replace("Z", "+00:00")).astimezone(UTC) - SYNC_OVERLAP
+            since = datetime.fromisoformat(state.cursor_value.replace("Z", "+00:00")).astimezone(UTC) - self._sync_overlap
             logger.info(
                 "Using sync cursor for %s actor=%s with overlap; since=%s",
                 service_name,
diff --git a/src/srht_contrib/main.py b/src/srht_contrib/main.py
index c6038cb..3737569 100644
--- a/src/srht_contrib/main.py
+++ b/src/srht_contrib/main.py
@@ -30,7 +30,7 @@ def build_poller(settings: Settings) -> PollerService:
     git_client = SourceHutGraphQLClient(settings.git_srht_endpoint, settings.srht_token)
     todo_service = TodoIngestionService(todo_client, settings)
     git_service = GitIngestionService(git_client, settings)
-    return PollerService(todo_service=todo_service, git_service=git_service)
+    return PollerService(todo_service=todo_service, git_service=git_service, settings=settings)
 
 
 def create_app(