# lambda_runtime_context

[![Cargo Test](https://github.com/quietscroll/lambda-runtime-context/actions/workflows/cargo-test.yml/badge.svg)](https://github.com/quietscroll/lambda-runtime-context/actions/workflows/cargo-test.yml)
[![docs.rs](https://img.shields.io/docsrs/lambda_runtime_context)](https://docs.rs/lambda_runtime_context)

Task-local runtime deadline helpers for async Rust workers.

`lambda_runtime_context` stores an invocation deadline in a Tokio task-local and exposes
small helpers for deciding whether enough execution time remains to start more
work. It is designed for AWS Lambda handlers, queue consumers, and other bounded
async runtimes where a worker should stop early and re-enqueue remaining work
before the platform terminates the process.

## Install

```toml
[dependencies]
lambda_runtime_context = "0.1"
```

## Core Idea

Wrap an async execution scope with a deadline timestamp in milliseconds since
the Unix epoch:

```rust
lambda_runtime_context::scope_deadline(deadline_ms, async {
    // Work in this async scope can read the deadline.
})
.await;
```

Then check the remaining time before starting expensive or non-interruptible
work:

```rust
use std::time::Duration;

if lambda_runtime_context::is_duration_available(Duration::from_secs(30)) {
    process_next_item().await;
} else {
    enqueue_remaining_work().await;
}
# async fn process_next_item() {}
# async fn enqueue_remaining_work() {}
```

## AWS Lambda Usage

AWS Lambda exposes an invocation deadline as milliseconds since the Unix epoch.
Pass that value into `scope_deadline` at the handler boundary:

```rust
use std::time::Duration;

async fn handle(deadline_ms: u64) {
    lambda_runtime_context::scope_deadline(deadline_ms, async {
        while lambda_runtime_context::is_duration_available(Duration::from_secs(30)) {
            process_next_message().await;
        }

        reenqueue_remaining_messages().await;
    })
    .await;
}

async fn process_next_message() {}
async fn reenqueue_remaining_messages() {}
```

`time_remaining()` returns `None` when no deadline has been scoped. This keeps
local development and tests explicit: code can choose whether missing context
means "do not start bounded work" or should be handled by a local fallback.

## Spawned Tasks

Tokio task-locals are scoped to the current task. A task created with
`tokio::spawn` does not automatically inherit the deadline. Capture the current
deadline and scope it again inside the spawned task:

```rust
async fn spawn_work() {
    if let Some(deadline_ms) = lambda_runtime_context::current_deadline_ms() {
        tokio::spawn(async move {
            lambda_runtime_context::scope_deadline(deadline_ms, async {
                do_work().await;
            })
            .await;
        });
    }
}

async fn do_work() {}
```

## API

- [`scope_deadline(deadline_ms, future)`](https://docs.rs/lambda_runtime_context/latest/lambda_runtime_context/fn.scope_deadline.html):
  runs a future with the deadline stored
  in task-local context.
- [`current_deadline_ms()`](https://docs.rs/lambda_runtime_context/latest/lambda_runtime_context/fn.current_deadline_ms.html):
  returns the scoped raw deadline timestamp for manual
  propagation into spawned tasks.
- [`time_remaining()`](https://docs.rs/lambda_runtime_context/latest/lambda_runtime_context/fn.time_remaining.html):
  returns the current remaining duration, or `None` when no
  deadline is scoped.
- [`total_time_limit()`](https://docs.rs/lambda_runtime_context/latest/lambda_runtime_context/fn.total_time_limit.html):
  returns the remaining duration using the scoped
  deadline. The function name is retained for compatibility.
- [`is_duration_available(duration)`](https://docs.rs/lambda_runtime_context/latest/lambda_runtime_context/fn.is_duration_available.html):
  returns `true` when at least `duration`
  remains before the deadline.

## Publishing

Before publishing:

```bash
cargo test -p lambda_runtime_context
cargo package -p lambda_runtime_context
```

Then publish from the workspace root:

```bash
cargo publish -p lambda_runtime_context
```

The crate is self-contained and only depends on `tokio` and `time`.
