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
2 changes: 1 addition & 1 deletion src/apify/_actor.py
Original file line number Diff line number Diff line change
Expand Up @@ -1398,7 +1398,7 @@ def _get_default_exit_process(self) -> bool:
def _get_remaining_time(self) -> timedelta | None:
"""Get time remaining from the Actor timeout. Returns `None` if not on an Apify platform."""
if self.is_at_home() and self.configuration.timeout_at:
return self.configuration.timeout_at - datetime.now(tz=timezone.utc)
return max(self.configuration.timeout_at - datetime.now(tz=timezone.utc), timedelta(0))

self.log.warning(
'Using `inherit` or `RemainingTime` argument is only possible when the Actor'
Expand Down
25 changes: 24 additions & 1 deletion tests/unit/actor/test_actor_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import asyncio
import warnings
from datetime import timedelta
from datetime import datetime, timedelta, timezone
from typing import TYPE_CHECKING

import pytest
Expand Down Expand Up @@ -321,3 +321,26 @@ async def test_get_remaining_time_warns_when_not_at_home(caplog: pytest.LogCaptu
result = Actor._get_remaining_time()
assert result is None
assert any('inherit' in msg or 'RemainingTime' in msg for msg in caplog.messages)


async def test_get_remaining_time_clamps_negative_to_zero() -> None:
"""Test that _get_remaining_time returns timedelta(0) instead of a negative value when timeout is in the past."""
async with Actor:
Actor.configuration.is_at_home = True
Actor.configuration.timeout_at = datetime.now(tz=timezone.utc) - timedelta(minutes=5)

result = Actor._get_remaining_time()
assert result is not None
assert result == timedelta(0)


async def test_get_remaining_time_returns_positive_when_timeout_in_future() -> None:
"""Test that _get_remaining_time returns a positive timedelta when timeout is in the future."""
async with Actor:
Actor.configuration.is_at_home = True
Actor.configuration.timeout_at = datetime.now(tz=timezone.utc) + timedelta(minutes=5)

result = Actor._get_remaining_time()
assert result is not None
assert result > timedelta(0)
assert result <= timedelta(minutes=5)