> ## Documentation Index
> Fetch the complete documentation index at: https://rasa.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Timer Stores

> Configure where Rasa Pro stores session timers to ensure they persist across restarts and in multi-pod deployments.

Rasa maintains one active timer per conversation to track inactivity. To ensure timers persist across server restarts and work in multi-pod deployments, Rasa uses a timer store.
Rasa provides built-in timer store implementations to suit different deployment scenarios and requirements.

## InMemoryTimerStore (default)

* **Description**

  `InMemoryTimerStore` is the default timer store and it stores timers in memory. Suitable for development and testing as timers are lost on server restart.
* **Configuration**

  To use the `InMemoryTimerStore` no configuration is needed.

## RedisTimerStore

### Description

`RedisTimerStore` maintains conversation timers using Redis as a persistence layer. This is the recommended option for production deployments as it supports persistence across server restarts and works in multi-pod environments.

With Redis:

* Timers survive server restarts.
* All pods in a horizontally-scaled deployment share the same timer state.
* Timers that expired while the server was down are recovered and processed on startup.

### Configuration

To set up the timer store with Redis the following steps are required:

1. Add required configuration to your `endpoints.yml`

```yaml theme={null}
timer_store:
    type: "redis"
    host: <host of the redis instance, e.g. localhost>
    port: <port of your redis instance, usually 6379>
    username: <username used for authentication>
    password: <password used for authentication>
    db: <number of your database within redis, e.g. 0. Not used in cluster mode>
    key_prefix: <alphanumeric value to prepend to timer store keys>
    socket_timeout: <time in seconds after which redis commands time out, default 10>
    poll_interval: <interval in seconds between polling for expired timers, default 1.0>
    # transit encryption parameters
    use_ssl: <whether or not the communication is encrypted, default false>
    ssl_keyfile: <path to an ssl private key, only used if use_ssl is true>
    ssl_certfile: <path to an ssl certificate, only used if use_ssl is true>
    ssl_ca_certs: <path to a file of concatenated CA certificates in PEM format, only used if use_ssl is true>
    # high availability parameters
    deployment_mode: <standard, cluster, or sentinel>
    endpoints: <list of redis cluster/sentinel node addresses in the format host:port>
    sentinel_service: <name of the redis sentinel service, only used in sentinel mode>
```

## Fallback Timer Store

If Redis is configured but becomes unavailable, Rasa automatically falls back to the `InMemoryTimerStore`.
Sessions continue to be managed without crashing, and a warning is logged when the fallback is activated.
When Redis recovers, Rasa resumes using it and logs that the fallback has been deactivated.

## Custom Timer Stores

If you need a timer store which is not available out of the box, you can implement your own.
To write a custom timer store, extend `SessionTimerStore` from `rasa.core.timer_stores.timer_store`.
Your constructor must accept an `endpoint_config` parameter:

```python theme={null}
from rasa.core.timer_stores.timer_store import SessionTimerStore
from rasa.utils.endpoints import EndpointConfig

class MyCustomTimerStore(SessionTimerStore):
  def __init__(self, endpoint_config: EndpointConfig = None):
      ...
```

Your custom timer store class must implement all of the following methods:

* `close`: releases any resources (connections, file handles, etc.) held by the store.
  Must respect the following signature:

```python theme={null}
  def close(self) -> None:
    """Close and clean up the timer store."""
```

* `store_timer`: persists a timer entry for a conversation. Must respect the following signature:

```python theme={null}
  async def store_timer(
    self,
    sender_id: str,
    session_id: Optional[str],
    scheduled_time: float,
    metadata: Optional[Dict[str, Any]] = None,
  ) -> None:
    """Store a session timer for the given conversation.

    Args:
        sender_id: The conversation ID.
        session_id: The current session ID, used to validate the timer
            has not been superseded when it fires.
        scheduled_time: Unix timestamp (seconds) when the timer should fire.
        metadata: Optional key-value data to attach to the timer.
    """
```

* `delete_timer`: removes a timer entry. Must respect the following signature:

```python theme={null}
  async def delete_timer(
    self,
    sender_id: str,
    only_if_scheduled_time: Optional[float] = None,
  ) -> bool:
    """Delete the timer for the given conversation.

    Args:
        sender_id: The conversation ID.
        only_if_scheduled_time: If set, delete only when the stored timer's
            scheduled_time equals this value (for atomic multi-pod claiming).
            If None, delete unconditionally.

    Returns:
        True if a timer was found and deleted, False otherwise.
    """
```

* `get_timer`: retrieves the current timer for a conversation, or None if none exists.
  Must respect the following signature:

```python theme={null}
  async def get_timer(self, sender_id: str) -> Optional[SessionTimer]:
    """Get the timer for the given conversation.

    Args:
        sender_id: The conversation ID.

    Returns:
        The SessionTimer if one exists for this conversation, None otherwise.
    """
```

* `get_expired_timers`: returns all timers whose `scheduled_time` is at or before `cutoff_time`.
  Must respect the following signature:

```python theme={null}
  async def get_expired_timers(
    self, cutoff_time: Optional[float] = None
  ) -> List[SessionTimer]:
    """Return all timers that have expired.

    Args:
        cutoff_time: Unix timestamp threshold. Timers with
            scheduled_time <= cutoff_time are returned.
            Defaults to the current time if None.

    Returns:
        List of expired SessionTimer objects. Must not delete them.
    """
```

The base class provides two helpers that can be used by the `get_expired_timers` method:

* `_check_time_for_expired(cutoff_time)`: returns `cutoff_time` if set, otherwise `time.time()`.
* `_filter_expired(timers, check_time)`: filters an iterable of `SessionTimer` objects to those with `scheduled_time <= check_time`.

Another built-in helper method available for use in your custom timer store is:

* `SessionTimer.create_timer(sender_id, session_id, scheduled_time, metadata)`: constructs a `SessionTimer` from the arguments passed to `store_timer`.

### Configuration

Put the module path to your custom timer store class in `endpoints.yml` under the `timer_store` key.
Any additional fields are passed through as part of the `EndpointConfig` and are accessible via `endpoint_config.kwargs`:

```yaml title="endpoints.yml" theme={null}
timer_store:
  type: path.to.your.module.MyCustomTimerStore
  a_parameter: a value
  another_parameter: another value
```


## Related topics

- [Session Timer](/docs/reference/config/session-management/session-timer.md)
- [Rasa Pro Change Log](/docs/reference/changelogs/rasa-pro-changelog.md)
- [Session Management Overview](/docs/reference/config/session-management/overview.md)
- [Session Lifecycle](/docs/reference/config/session-management/session-lifecycle.md)
- [Tracker Stores](/docs/reference/integrations/tracker-stores.md)
