Skip to content

Commit eb6576b

Browse files
committed
Merge branch 'main' into config-via-env
2 parents 4fb3a19 + 70f3a52 commit eb6576b

File tree

22 files changed

+398
-68
lines changed

22 files changed

+398
-68
lines changed

.devcontainer/README.md

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
# Devcontainer Configurations
2+
3+
This directory contains multiple devcontainer configurations for different use cases.
4+
5+
## 📋 Available Configurations
6+
7+
### 1. `devcontainer.json` - **User/Demo** (Default)
8+
- **Purpose**: Quick start for new users or demos
9+
- **Docker Strategy**: Pulls pre-built images from Docker Hub
10+
- **Speed**: ⚡ Fast startup (30-60 seconds)
11+
- **Use Cases**:
12+
- New users trying out anomstack
13+
- Demos and presentations
14+
- Quick testing without development setup
15+
16+
### 2. `devcontainer.dev.json` - **Development**
17+
- **Purpose**: Full development environment
18+
- **Docker Strategy**: Builds images locally with source code changes
19+
- **Speed**: 🐌 Slower startup (3-5 minutes)
20+
- **Use Cases**:
21+
- Active development on anomstack
22+
- Testing code changes
23+
- Contributing to the project
24+
25+
## 🚀 How to Use
26+
27+
### GitHub Codespaces
28+
29+
1. **Default (User/Demo)**: Just click "Create codespace" - uses `devcontainer.json`
30+
2. **Development**: When creating a codespace, click "..." → "Configure dev container" → select `devcontainer.dev.json`
31+
32+
### VS Code Dev Containers
33+
34+
1. **Default**: Open folder in VS Code → "Reopen in Container"
35+
2. **Development**:
36+
- Open Command Palette (`Ctrl+Shift+P`)
37+
- "Dev Containers: Reopen in Container"
38+
- Select `devcontainer.dev.json`
39+
40+
### Manual Selection
41+
42+
You can also rename the files to switch defaults:
43+
```bash
44+
# Switch to development as default
45+
mv devcontainer.json devcontainer.user.json
46+
mv devcontainer.dev.json devcontainer.json
47+
```
48+
49+
## 🏗️ What Each Configuration Does
50+
51+
### Both Configurations
52+
- Set up VS Code extensions for Python, Docker, and development
53+
- Forward ports: 3000 (Dagster), 5001 (Dashboard), 5432 (PostgreSQL)
54+
- Run initialization and post-create scripts
55+
- Enable Docker-in-Docker support
56+
57+
### Key Differences
58+
| Feature | User/Demo | Development |
59+
|---------|-----------|-------------|
60+
| Docker Images | Pull from Hub | Build locally |
61+
| Startup Time | ~60 seconds | ~5 minutes |
62+
| Code Changes | View only | Full development |
63+
| Extensions | Basic set | Extended dev tools |
64+
65+
## 🎯 Recommendations
66+
67+
- **First time users**: Use default `devcontainer.json`
68+
- **Regular development**: Use `devcontainer.dev.json`
69+
- **Demos/presentations**: Use default `devcontainer.json`
70+
- **Contributing**: Use `devcontainer.dev.json`
71+
72+
## 🔧 Services Available
73+
74+
Both configurations provide:
75+
- **Dagster Webserver**: [http://localhost:3000](http://localhost:3000)
76+
- **Anomstack Dashboard**: [http://localhost:5001](http://localhost:5001)
77+
- **PostgreSQL Database**: `localhost:5432`
78+
79+
## 📚 Documentation
80+
81+
For more information, see the main [README.md](../README.md) and [DOCKER.md](../DOCKER.md) files.
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
{
2+
"name": "anomstack (Development)",
3+
"dockerComposeFile": [
4+
"../docker-compose.yaml",
5+
"../docker-compose.dev.yaml"
6+
],
7+
"service": "anomstack_code",
8+
"workspaceFolder": "/opt/dagster/app",
9+
"forwardPorts": [3000, 5001, 5432],
10+
"portsAttributes": {
11+
"3000": {
12+
"label": "Dagster Webserver",
13+
"onAutoForward": "notify"
14+
},
15+
"5001": {
16+
"label": "Dashboard",
17+
"onAutoForward": "notify"
18+
},
19+
"5432": {
20+
"label": "PostgreSQL",
21+
"onAutoForward": "silent"
22+
}
23+
},
24+
"remoteUser": "root",
25+
"initializeCommand": "bash .devcontainer/initialize.sh",
26+
"postCreateCommand": [
27+
"bash",
28+
"-c",
29+
"chmod +x .devcontainer/post_create_command.sh && bash .devcontainer/post_create_command.sh"
30+
],
31+
"customizations": {
32+
"vscode": {
33+
"extensions": [
34+
"github.copilot",
35+
"github.copilot-chat",
36+
"ms-azuretools.vscode-docker",
37+
"ms-vscode.makefile-tools",
38+
"ms-python.python",
39+
"ms-python.pylint",
40+
"ms-python.black-formatter",
41+
"ms-python.isort",
42+
"ms-python.flake8"
43+
]
44+
}
45+
},
46+
"features": {
47+
"ghcr.io/devcontainers/features/docker-in-docker:2": {}
48+
},
49+
"shutdownAction": "stopCompose"
50+
}

.devcontainer/devcontainer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"name": "anomstack",
2+
"name": "anomstack (User/Demo)",
33
"dockerComposeFile": "../docker-compose.yaml",
44
"service": "anomstack_code",
55
"workspaceFolder": "/opt/dagster/app",

.devcontainer/initialize.sh

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,37 @@ mkdir -p tmp
1818
# Create dagster_home directory at the same path used by Docker Compose
1919
mkdir -p /opt/dagster/dagster_home
2020

21+
# Set python_ingest_simple example jobs to RUNNING for GitHub Codespaces
22+
PYTHON_INGEST_CONFIG="metrics/examples/python/python_ingest_simple/python_ingest_simple.yaml"
23+
if [ -f "$PYTHON_INGEST_CONFIG" ]; then
24+
echo "Updating python_ingest_simple job schedules to RUNNING for Codespaces..."
25+
26+
# Array of schedule statuses to set to RUNNING
27+
SCHEDULE_STATUSES=(
28+
"ingest_default_schedule_status"
29+
"train_default_schedule_status"
30+
"score_default_schedule_status"
31+
"alert_default_schedule_status"
32+
)
33+
34+
# Update each schedule status
35+
for status in "${SCHEDULE_STATUSES[@]}"; do
36+
if grep -q "$status:" "$PYTHON_INGEST_CONFIG"; then
37+
# Replace existing line
38+
sed -i "s/${status}:.*/${status}: \"RUNNING\"/" "$PYTHON_INGEST_CONFIG"
39+
echo "Updated existing $status to RUNNING"
40+
else
41+
# Add new line after metric_batch line
42+
sed -i "/^metric_batch:/a ${status}: \"RUNNING\"" "$PYTHON_INGEST_CONFIG"
43+
echo "Added $status: RUNNING"
44+
fi
45+
done
46+
47+
echo "Updated python_ingest_simple job schedules to RUNNING"
48+
else
49+
echo "Warning: python_ingest_simple.yaml not found at $PYTHON_INGEST_CONFIG"
50+
fi
51+
2152
# Any other pre-container setup can go here
2253
# For example:
2354
# - Download required files

.example.env

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,11 +95,12 @@ ANOMSTACK_LLM_PLATFORM=openai
9595
# some dagster env vars
9696
DAGSTER_LOG_LEVEL=DEBUG
9797
DAGSTER_CONCURRENCY=4
98-
DAGSTER_HOME=/opt/dagster/dagster_home
9998

10099
# max runtime for a job in dagster
101100
# https://docs.dagster.io/deployment/run-monitoring#general-run-timeouts
102101
ANOMSTACK_MAX_RUNTIME_SECONDS_TAG=3600
102+
# kill runs that exceed this many minutes
103+
ANOMSTACK_KILL_RUN_AFTER_MINUTES=60
103104

104105
# postgres related env vars
105106
ANOMSTACK_POSTGRES_USER=postgres_user
@@ -126,4 +127,4 @@ ANOMSTACK_CLICKHOUSE_DATABASE=default
126127
ANOMSTACK_DASHBOARD_PORT = 5001
127128

128129
# PostHog API key for analytics
129-
POSTHOG_API_KEY=
130+
POSTHOG_API_KEY=

CONTRIBUTING.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ We want your work to be readable by others; therefore, we encourage you to note
146146
- All new code should include appropriate tests. See the [`tests/README.md`](./tests/README.md) for detailed testing guidelines.
147147
- Run the full test suite before submitting: `pytest tests/`
148148
- Check test coverage: `pytest tests/ --cov=anomstack --cov-report=term-missing`
149-
- The project currently maintains **64% test coverage**. Contributions that increase coverage are especially welcome!
149+
- The project currently maintains **63% test coverage**. Contributions that increase coverage are especially welcome!
150150

151151
#### Updating the Coverage Badge
152152

Makefile

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@ SHELL=/bin/bash
66

77
.PHONY: local locald kill-locald ps-locald dev
88

9-
# start dagster locally
9+
# start dagster locally (simple - just set DAGSTER_HOME directly)
1010
local:
11-
dagster dev -f anomstack/main.py
11+
DAGSTER_HOME=$$(pwd)/dagster_home dagster dev -f anomstack/main.py
1212

1313
# start dagster locally as a daemon with no log file
1414
locald:
@@ -30,7 +30,7 @@ dev:
3030
# DOCKER OPERATIONS
3131
# =============================================================================
3232

33-
.PHONY: docker docker-dev docker-build docker-dev-build docker-tag docker-push docker-build-push
33+
.PHONY: docker docker-dev docker-smart docker-build docker-dev-build docker-tag docker-push docker-build-push
3434
.PHONY: docker-pull docker-clean docker-logs docker-logs-code docker-logs-dagit docker-logs-daemon docker-logs-dashboard
3535
.PHONY: docker-shell-code docker-shell-dagit docker-shell-dashboard docker-restart-dashboard docker-restart-code
3636
.PHONY: docker-stop docker-down docker-rm docker-prune
@@ -39,6 +39,17 @@ dev:
3939
docker:
4040
docker compose up -d
4141

42+
# smart docker start: try to pull, fallback to build if images don't exist
43+
docker-smart:
44+
@echo "🔄 Attempting to pull pre-built images..."
45+
@if docker compose pull 2>/dev/null; then \
46+
echo "✅ Successfully pulled images, starting containers..."; \
47+
docker compose up -d; \
48+
else \
49+
echo "⚠️ Pull failed, building images locally..."; \
50+
make docker-dev-build && make docker-dev; \
51+
fi
52+
4253
# start docker containers with local development images
4354
docker-dev:
4455
docker compose -f docker-compose.yaml -f docker-compose.dev.yaml up -d
@@ -113,10 +124,6 @@ docker-restart-dashboard:
113124
docker-restart-code:
114125
docker compose restart anomstack_code
115126

116-
# stop all containers
117-
docker-stop:
118-
docker compose down
119-
120127
# alias for docker-stop
121128
docker-down:
122129
docker compose down
@@ -202,8 +209,20 @@ requirements-install:
202209
# UTILITIES
203210
# =============================================================================
204211

205-
.PHONY: posthog-example
212+
.PHONY: posthog-example kill-long-runs
206213

207214
# run the PostHog example ingest function
208215
posthog-example:
209216
python scripts/posthog_example.py
217+
218+
# kill any dagster runs exceeding configured timeout
219+
kill-long-runs:
220+
python scripts/kill_long_running_tasks.py
221+
222+
# run docker in dev mode with correct environment
223+
docker-dev-env:
224+
docker compose -f docker-compose.yaml -f docker-compose.dev.yaml up -d
225+
226+
# stop docker containers
227+
docker-stop:
228+
docker compose -f docker-compose.yaml -f docker-compose.dev.yaml down

README.md

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
<a href="https://github.com/andrewm4894/anomstack/blob/main/LICENSE">![License](https://img.shields.io/badge/License-MIT-yellow.svg)</a>
1414
<a href="https://github.com/andrewm4894/anomstack/actions/workflows/pytest.yaml">![GitHub PyTest Workflow Status](https://img.shields.io/github/actions/workflow/status/andrewm4894/anomstack/pytest.yaml?label=Tests)</a>
1515
<a href="https://github.com/andrewm4894/anomstack/actions/workflows/pre-commit.yaml">![GitHub Pre-Commit Workflow Status](https://img.shields.io/github/actions/workflow/status/andrewm4894/anomstack/pre-commit.yaml?label=Pre-Commit)</a>
16-
<a href="./tests/README.md#coverage-report">![Coverage](https://img.shields.io/badge/Coverage-64%25-yellow?logo=pytest)</a>
16+
<a href="./tests/README.md#coverage-report">![Coverage](https://img.shields.io/badge/Coverage-63%25-yellow?logo=pytest)</a>
1717

1818
</div>
1919

@@ -654,6 +654,18 @@ Below you see an example of an LLM alert via email. In this case we add a descri
654654
655655
</details>
656656
657+
## Killing Long Running Jobs
658+
659+
Sometimes Dagster runs can get stuck. Anomstack ships with a sensor that
660+
terminates any run exceeding a configurable timeout. By default runs are killed
661+
after 60 minutes. You can override this in your `dagster.yaml` or via the
662+
`ANOMSTACK_KILL_RUN_AFTER_MINUTES` environment variable. You can also invoke the
663+
cleanup manually with:
664+
665+
```bash
666+
make kill-long-runs
667+
```
668+
657669
## Contributing
658670

659671
Read the [contributing guide](./CONTRIBUTING.md) to learn about our development process, how to propose bugfixes and improvements, and how to build and test your changes to Anomstack.

anomstack/main.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
from anomstack.jobs.summary import summary_jobs, summary_schedules
1515
from anomstack.jobs.train import train_jobs, train_schedules
1616
from anomstack.sensors.failure import email_on_run_failure
17+
from anomstack.sensors.timeout import kill_long_running_runs
1718

1819
jobs = (
1920
ingest_jobs
@@ -26,7 +27,7 @@
2627
+ summary_jobs
2728
+ delete_jobs
2829
)
29-
sensors = [email_on_run_failure]
30+
sensors = [email_on_run_failure, kill_long_running_runs]
3031
schedules = (
3132
ingest_schedules
3233
+ train_schedules

0 commit comments

Comments
 (0)