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
4 changes: 2 additions & 2 deletions apps/api/src/five08/backend/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -586,7 +586,7 @@ def _crm_sync_idempotency_key(*, now: datetime) -> str:


def _newsletter_sync_idempotency_key(*, now: datetime) -> str:
interval_seconds = max(1, settings.newsletter_sync_interval_seconds)
interval_seconds = max(60, settings.newsletter_sync_interval_seconds)
bucket = int(now.timestamp()) // interval_seconds
return f"newsletter-sync:508-members:{bucket}"

Expand Down Expand Up @@ -718,7 +718,7 @@ async def _crm_sync_scheduler(app: FastAPI) -> None:

async def _newsletter_sync_scheduler(app: FastAPI) -> None:
queue = app.state.queue
interval_seconds = max(1, settings.newsletter_sync_interval_seconds)
interval_seconds = max(60, settings.newsletter_sync_interval_seconds)
while True:
try:
await _enqueue_newsletter_sync_job(queue, reason="scheduler")
Expand Down
2 changes: 1 addition & 1 deletion packages/shared/src/five08/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ class SharedSettings(BaseSettings):
)
keila_api_timeout_seconds: float = 20.0
newsletter_sync_enabled: bool = True
newsletter_sync_interval_seconds: int = 604800
newsletter_sync_interval_seconds: int = Field(default=604800, ge=60)
newsletter_sync_excluded_mailboxes: str = ""
onboarding_email_smtp_server: str | None = Field(
default=None,
Expand Down
12 changes: 5 additions & 7 deletions tests/integration/test_dashboard_playwright.py
Original file line number Diff line number Diff line change
Expand Up @@ -355,7 +355,6 @@ def test_dashboard_interactivity_with_playwright(dashboard_server: str) -> None:
assign_onboarder_requested = threading.Event()
update_onboarding_status_requested = threading.Event()
detail_requested = threading.Event()
gig_application_requested = threading.Event()
gig_application_add_requested = threading.Event()
gig_list_requests: list[str] = []
gig_detail_requests: list[str] = []
Expand Down Expand Up @@ -540,7 +539,6 @@ def notifications_route(route: Any) -> None:
)

def gig_application_status_route(route: Any) -> None:
gig_application_requested.set()
body = route.request.post_data_json
assert body["status"] == "unavailable"
casey_application_id = "22222222-2222-4222-8222-222222222222"
Expand Down Expand Up @@ -761,19 +759,19 @@ def sync_route(route: Any) -> None:
casey_status = page.get_by_label("Candidate status for Casey Candidate")
expect(casey_status).to_be_enabled()
expect(casey_status).to_have_value("suggested")
with page.expect_request(
lambda request: (
request.method == "POST"
and request.url.endswith(
with page.expect_response(
lambda response: (
response.request.method == "POST"
and response.url.endswith(
"/dashboard/api/gigs/"
"11111111-1111-4111-8111-111111111111"
"/applications/"
"22222222-2222-4222-8222-222222222222/status"
)
and response.status == 200
)
):
casey_status.select_option("unavailable")
assert gig_application_requested.wait(timeout=5)
expect(casey_status).to_have_value("unavailable")
assert gig_detail_requests

Expand Down
13 changes: 13 additions & 0 deletions tests/unit/test_backend_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -7089,6 +7089,19 @@ async def test_manual_newsletter_sync_idempotency_keys_are_unique() -> None:
assert all(key.startswith("newsletter-sync:508-members:dashboard:") for key in keys)


def test_newsletter_sync_idempotency_key_clamps_interval_floor(
monkeypatch: pytest.MonkeyPatch,
) -> None:
"""Scheduler idempotency buckets should keep the same one-minute floor as settings."""
monkeypatch.setattr(api.settings, "newsletter_sync_interval_seconds", 1)

key = api._newsletter_sync_idempotency_key(
now=datetime(1970, 1, 1, 0, 1, 30, tzinfo=timezone.utc),
)

assert key == "newsletter-sync:508-members:1"


def test_dashboard_sync_newsletters_workflows_engineer_is_dry_run(
client: TestClient,
) -> None:
Expand Down
10 changes: 10 additions & 0 deletions tests/unit/test_shared_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,16 @@ def test_shared_settings_brevo_members_list_id_accepts_numeric_string() -> None:
assert settings.brevo_508_members_newsletter_list_id == 4


def test_shared_settings_newsletter_sync_interval_requires_one_minute() -> None:
"""Newsletter scheduler intervals should match dashboard runtime-config limits."""
with pytest.raises(ValidationError):
SharedSettings(newsletter_sync_interval_seconds=59)

settings = SharedSettings(newsletter_sync_interval_seconds=60)

assert settings.newsletter_sync_interval_seconds == 60


def test_local_service_defaults_target_host_runtime(
monkeypatch: pytest.MonkeyPatch,
) -> None:
Expand Down