Do we need a timeout mechanism? · Issue #636 · QData/TextAttack · GitHub
Skip to content

Do we need a timeout mechanism? #636

Open

Description

@wenh06

Is your feature request related to a problem? Please describe.
Some attack recipes are extremely slow, so a timeout mechanism for a single attack on one sample is needed.

Describe the solution you'd like
Use a timeout context manager like

@contextmanager
def timeout(duration: float):
    """
    A context manager that raises a `TimeoutError` after a specified time.

    Parameters
    ----------
    duration: float,
        the time duration in seconds,
        should be non-negative,
        0 for no timeout

    References
    ----------
    https://stackoverflow.com/questions/492519/timeout-on-a-function-call

    """
    if np.isinf(duration):
        duration = 0
    elif duration < 0:
        raise ValueError("duration must be non-negative")
    elif duration > 0:  # granularity is 1 second, so round up
        duration = max(1, int(duration))

    def timeout_handler(signum, frame):
        raise TimeoutError(f"block timedout after {duration} seconds")

    signal.signal(signal.SIGALRM, timeout_handler)
    signal.alarm(duration)
    yield
    signal.alarm(0)

and replace this line

result = self._attack(goal_function_result)

with, for example,

try:
    with timeout(duration=time_out):
        result = self._attack(goal_function_result)
except TimeoutError:
    result = FailedAttackResult(goal_function_result, goal_function_result)
except Exception as e:
    if ignore_errors:
        # print(e)
        result = FailedAttackResult(
            goal_function_result, goal_function_result
        )
    else:
        raise e

One can also add a time-out argument in commands.textattack_cli, and pass this argument in related classes and functions.

Describe alternatives you've considered
NA

Additional context
NA

Activity

  1. jxmorris12 commented on May 25, 2022

    @jxmorris12
    Collaborator

    I think this is a great idea @wenh06. The attack search process is exponential in nature so it's easy to get into a state where the attack will never finish in a reasonable amount of time. It could also be nice to try and predict how long the attack would take, and warn the user if they're running something that is very very slow.

  2. jxmorris12 commented on Jun 9, 2022

    @jxmorris12
    Collaborator

    Just thinking about this a little more:

    • There are lots of ways to make functions time out in Python. Maybe asyncio is nicest, but it might cause problems – like weird error messages when things break – if all the important code is running asynchronously.
    • We should probably add a new type of attack result, like TimedOutAttackResult or ExpiredAttackResult or something like that, and show it in the results (X skipped, Y succeeded, Z failed, and M timed out) if users specify a timeout.
      • Alternatively maybe we could just consider a timeout a failure (this is what query budget does) but that could be confusing, since it wouldn't be clear how something failed. (Though maybe it's confusing for query budget too..)
  3. kenneth-ge commented on Mar 10, 2024

    @kenneth-ge

    Bump on this! I really like this, and have had to implement a custom timeout feature in my own production code, so this would definitely be really useful. The issue is that most attacks finish in just a couple minutes, but some small proportion of attacks take more than 2 days to finish, so having a timeout mechanism allows us to finish most of our attacks in a reasonable amount of time

  4. qiyanjun commented on Aug 13, 2026

    @qiyanjun
    Member

    Still relevant, and the design thread above (new `TimedOutAttackResult` vs. treating timeout as failure, cross-platform interrupt mechanism, interaction with `--parallel` worker timeouts) never reached a conclusion — that's real design work, not something I want to unilaterally decide and merge as a "fix." No code change from me here; flagging that this is still open and well-scoped for whoever picks it up, with the open design questions being: (1) new result type or reuse `FailedAttackResult`, (2) signal-based vs. thread/process-based timeout (signal-based doesn't work well cross-platform or inside multiprocessing workers), (3) per-example vs. whole-dataset budget.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions