Uptime Monitor is a serverless AWS project built with Go, Lambda, EventBridge, S3, OpenTofu (Terraform-compatible), and GitHub Actions.
It monitors multiple websites on an hourly schedule, stores the latest status snapshot and recent history in S3, and exposes lightweight HTTP endpoints through a Lambda Function URL for manual checks and dashboard data.
| Case Study | Problem | How it was diagnosed | Result |
|---|---|---|---|
| Why S3 JSON storage | The monitor needed persistent latest status and short per-site history without adding database infrastructure. | S3 fit because the MVP only needed small structured writes, current-state reads, and short history reads; it did not need relational queries, indexes, joins, or high-write throughput. | Results are stored as latest.json and history.json, keeping storage low-cost, frontend-friendly, and database-free for the MVP. |
| Why EventBridge scheduling | The monitor needed to run automatically without relying on a user or external client to call /check. |
EventBridge fit because it keeps the scheduler serverless, avoids a VM cron job or always-on worker, and supports the hourly cadence needed for the first version. | EventBridge invokes the Lambda every hour with rate(1 hour), reusing the same monitor path as manual checks. |
The system runs as a small serverless monitoring loop: Terraform provisions AWS resources, EventBridge triggers scheduled Lambda checks, and S3 stores the latest and historical status data.
| Path | Use case | Flow |
|---|---|---|
| Scheduled monitoring | Check configured websites every hour | EventBridge -> Lambda -> monitored sites -> S3 |
| Manual operation | Trigger checks or read monitor data on demand | Lambda Function URL -> /check, /latest, /history, /health |
| Runtime storage | Keep latest and recent historical status data | Lambda -> S3 latest.json and history.json |
| Infrastructure deployment | Keep AWS resources managed from source control | GitHub Actions -> Terraform -> AWS resources |
Deployment flow:
flowchart LR
Source["GitHub Repository"]
Actions["GitHub Actions"]
Terraform["Terraform"]
AWS["Lambda, S3, EventBridge, IAM"]
Source --> Actions
Actions --> Terraform
Terraform --> AWS
Runtime flow:
flowchart LR
Schedule["EventBridge"]
Lambda["AWS Lambda"]
Health["GET /health"]
Check["POST /check"]
Latest["GET /latest"]
History["GET /history"]
Sites["Monitored sites"]
Store["Storage layer"]
LatestFile["latest.json"]
HistoryFile["history.json"]
S3["S3 bucket"]
Schedule -- every hour --> Lambda
Lambda --> Health
Lambda --> Check
Lambda --> Latest
Lambda --> History
Check -- run checks --> Sites
Sites -- results --> Check
Check -- save results --> Store
Store -- write --> LatestFile
Store -- update --> HistoryFile
LatestFile -- store --> S3
HistoryFile -- store --> S3
Latest -- read latest.json --> S3
History -- read history.json --> S3
| Layer | Tools |
|---|---|
| Language | Go |
| Compute | AWS Lambda |
| Scheduling | Amazon EventBridge |
| Storage | Amazon S3 |
| Infrastructure | Terraform |
| Testing | Go testing package, table-driven tests |
| CI/CD | GitHub Actions |
| Endpoint | Method | Purpose |
|---|---|---|
/health |
GET |
Returns Lambda service health |
/check |
POST |
Runs uptime checks and writes results to S3 |
/latest |
GET |
Returns the latest status snapshot |
/history |
GET |
Returns recent status history grouped by URL |
Build and test the Go backend:
make test
make lambda-packageDeploy infrastructure locally:
cd infra
tofu init
tofu applyTrigger a manual check:
curl -X POST "$(tofu output -raw lambda_function_url)check"Read monitor data:
curl "$(tofu output -raw lambda_function_url)latest"
curl "$(tofu output -raw lambda_function_url)history"