Skip to content

Commit 14173ea

Browse files
committed
Initial commit
1 parent 5bd0aea commit 14173ea

File tree

5 files changed

+158
-0
lines changed

5 files changed

+158
-0
lines changed

Cargo.toml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
[package]
2+
name = "lambda-action-filter"
3+
version = "0.1.0"
4+
edition = "2021"
5+
6+
[dependencies]
7+
lambda_runtime = "0.9"
8+
serde = { version = "1.0", features = ["derive"] }
9+
serde_json = "1.0"
10+
tokio = { version = "1", features = ["macros", "rt-multi-thread"] }
11+
chrono = { version = "0.4", features = ["serde"] }

README.md

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
# Rust Lambda Assignment: Action Filter
2+
3+
This repository contains a **broken** AWS Lambda written in Rust. Your task is to debug and fix it so that it compiles, runs locally, and produces correct results.
4+
5+
## 📋 Scenario
6+
7+
The Lambda receives a JSON list of **actions**, each with:
8+
9+
* `entity_id` — string identifier
10+
* `last_action_time` — ISO‑8601 timestamp
11+
* `next_action_time` — ISO‑8601 timestamp
12+
* `priority``"high"` or `"low"`
13+
14+
### Business Rules
15+
16+
1. **At most one** action per `entity_id`.
17+
2. Only include actions where **`next_action_time` is within 90 days** of *today*.
18+
3. **High‑priority** actions should appear **first** in the output.
19+
4. Skip any action where **`last_action_time` is < 7 days ago**.
20+
21+
Unfortunately, the code has **three deliberate problems**:
22+
23+
| Type | What you’ll see |
24+
|------|-----------------|
25+
| Compilation error | Lifetime/key mismatch in a `HashMap` declaration |
26+
| Runtime panic | Timestamp math can panic with certain input |
27+
| Logic bug | Priority sorting is wrong (`"high"` can end up after `"low"`) |
28+
29+
## 🛠 Getting Started
30+
31+
1. **Install Rust** (stable) and [cargo‑lambda](https://github.com/cargo-lambda/cargo-lambda):
32+
33+
```bash
34+
rustup update stable
35+
cargo install cargo-lambda
36+
```
37+
38+
2. **Run the Lambda locally** with sample data:
39+
40+
```bash
41+
cargo lambda invoke --data-file testdata/sample-input.json
42+
```
43+
44+
You should observe a compilation error first. Fix it, then re‑run to expose the panic and logic bug.
45+
46+
3. **Fix all three problems** so the Lambda prints a correct, filtered list.
47+
48+
## ✅ Acceptance Criteria
49+
50+
* The project **compiles cleanly** (`cargo check` passes).
51+
* `cargo lambda invoke …` returns the correct, filtered JSON.
52+
* No panics for well‑formed input.
53+
* Clear, idiomatic Rust code with proper error handling and logging (`tracing` or `log` welcome).
54+
55+
## 🧪 Optional Stretch Goals
56+
57+
* Add unit tests in `tests/`.
58+
* Improve error messages and JSON schema validation.
59+
* Propose a CDK deploy step or GitHub Actions workflow.
60+
61+
Good luck — happy debugging!

src/main.rs

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
use std::collections::HashMap;
2+
3+
use chrono::{DateTime, Duration, Utc};
4+
use lambda_runtime::{handler_fn, Context, Error};
5+
use serde::{Deserialize, Serialize};
6+
use serde_json::{json, Value};
7+
8+
#[derive(Debug, Deserialize, Serialize, Clone)]
9+
struct Action {
10+
entity_id: String,
11+
last_action_time: DateTime<Utc>,
12+
next_action_time: DateTime<Utc>,
13+
priority: String,
14+
}
15+
16+
#[tokio::main]
17+
async fn main() -> Result<(), Error> {
18+
let func = handler_fn(filter_actions);
19+
lambda_runtime::run(func).await?;
20+
Ok(())
21+
}
22+
23+
async fn filter_actions(event: Value, _: Context) -> Result<Value, Error> {
24+
let now = Utc::now();
25+
26+
let input: Vec<Action> = serde_json::from_value(event)?;
27+
28+
// ⛔ COMPILATION ERROR: &str used as HashMap key with non-'static lifetime
29+
let mut selected: HashMap<&str, Action> = HashMap::new();
30+
31+
for action in input {
32+
// 💥 RUNTIME PANIC possibility if last_action_time is malformed or in the future
33+
let days_since_last = (now - action.last_action_time).num_days();
34+
if days_since_last < 7 {
35+
continue;
36+
}
37+
38+
if action.next_action_time > now + Duration::days(90) {
39+
continue;
40+
}
41+
42+
// Keep at most one action per entity
43+
selected
44+
.entry(&action.entity_id)
45+
.or_insert(action);
46+
}
47+
48+
let mut actions: Vec<Action> = selected.into_iter().map(|(_, v)| v).collect();
49+
50+
// ⚠️ BUSINESS LOGIC BUG: lexicographic sort—"high" comes after "low"
51+
actions.sort_by_key(|a| a.priority.clone());
52+
53+
Ok(json!(actions))
54+
}

testdata/sample-input.json

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
[
2+
{
3+
"entity_id": "user1",
4+
"last_action_time": "2025-06-20T00:00:00Z",
5+
"next_action_time": "2025-07-10T00:00:00Z",
6+
"priority": "high"
7+
},
8+
{
9+
"entity_id": "user1",
10+
"last_action_time": "2025-06-01T00:00:00Z",
11+
"next_action_time": "2025-07-01T00:00:00Z",
12+
"priority": "low"
13+
},
14+
{
15+
"entity_id": "user2",
16+
"last_action_time": "2025-03-01T00:00:00Z",
17+
"next_action_time": "2026-01-01T00:00:00Z",
18+
"priority": "high"
19+
},
20+
{
21+
"entity_id": "user3",
22+
"last_action_time": "2025-05-01T00:00:00Z",
23+
"next_action_time": "2025-07-10T00:00:00Z",
24+
"priority": "low"
25+
}
26+
]

tests/filter_tests.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
use lambda_action_filter::main as lambda_main; // Adjust if crate name changes
2+
// Placeholder for integration tests; candidates can extend
3+
#[test]
4+
fn dummy() {
5+
assert_eq!(2 + 2, 4);
6+
}

0 commit comments

Comments
 (0)