Skip to content

Commit d1ab9de

Browse files
committed
Make this an API.
1 parent b80671e commit d1ab9de

File tree

9 files changed

+157
-61
lines changed

9 files changed

+157
-61
lines changed

Diff for: .dockerignore

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
node_modules
2+
npm-debug.log
3+
Dockerfile
4+
.dockerignore
5+
.git
6+
.gitignore
7+
*.pyc
8+
__pycache__/
9+
.env
10+
.venv/

Diff for: Dockerfile

+54
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
# Use an official Python runtime as the base image
2+
FROM python:3.8-slim
3+
4+
# Set environment variables
5+
ENV PYTHONUNBUFFERED=1 \
6+
POETRY_VERSION=1.4.0 \
7+
POETRY_VIRTUALENVS_CREATE=false \
8+
POETRY_CACHE_DIR=/var/cache/pypoetry
9+
10+
# Install system dependencies and Poetry
11+
RUN apt-get update && apt-get install -y --no-install-recommends \
12+
curl \
13+
gcc \
14+
git \
15+
&& curl -sSL https://install.python-poetry.org | python3 - \
16+
&& ln -s /root/.local/bin/poetry /usr/local/bin/poetry \
17+
&& apt-get purge -y --auto-remove curl gcc git \
18+
&& rm -rf /var/lib/apt/lists/*
19+
20+
# Set the working directory
21+
WORKDIR /app
22+
23+
# Copy Poetry configuration files
24+
COPY pyproject.toml poetry.lock ./
25+
26+
# Copy the application code before installing dependencies
27+
COPY automation/ automation/
28+
COPY utils/ utils/
29+
COPY monitoring/ monitoring/
30+
COPY prediction/ prediction/
31+
32+
# Copy other files we need
33+
COPY scripts/ scripts/
34+
COPY config.yaml .
35+
COPY data/ data/
36+
COPY README.md .
37+
38+
# Copy the main entry point
39+
COPY main.py .
40+
41+
# Install project dependencies using the updated Poetry command
42+
RUN poetry install --no-dev --no-interaction --no-ansi
43+
44+
# Create necessary directories for logs and data
45+
RUN mkdir -p data logs
46+
47+
# Set environment variables for Fly.io (modify as needed)
48+
ENV FLY_APP_NAME=your-fly-app-name
49+
50+
# Expose ports if your application uses any (modify if necessary)
51+
# EXPOSE 8000
52+
53+
# Define the default command to run your application
54+
CMD ["python", "main.py"]

Diff for: FUTURE.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Sanity Check: Is This Approach Worth Continuing?
22

3-
Hey fellow devs! I've been working on this auto-placement system for Fly.io, and I wanted to share my thoughts on whether it's worth pursuing further. Short answer: yes, but we need to make some tweaks.
3+
I wanted to share my thoughts on whether it's worth pursuing further. Short answer: yes, but we need to make some tweaks.
44

55
## Current Approach
66

Diff for: automation/auto_placer.py

+19-7
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import os
88
import subprocess
99
import yaml
10+
import json
1011
from datetime import datetime, timedelta
1112
from monitoring.traffic_monitor import collect_region_traffic
1213
from utils.history_manager import update_traffic_history
@@ -15,6 +16,7 @@
1516
from utils.fancy_logger import get_logger, log_action
1617
from dateutil.parser import isoparse
1718

19+
1820
logger = get_logger(__name__)
1921

2022
# Load configuration
@@ -96,18 +98,28 @@ def main():
9698
current_data = collect_region_traffic()
9799
logger.debug(f"Current traffic data: {current_data}")
98100

99-
print("Updating traffic history...")
101+
logger.info("Updating traffic history...")
100102
history = update_traffic_history(current_data)
101103

102-
print("Retrieving current deployment regions...")
104+
logger.info("Retrieving current deployment regions...")
103105
current_regions = get_current_regions()
104106

105-
print("Predicting placement actions...")
107+
logger.info("Predicting placement actions...")
106108
regions_to_deploy, regions_to_remove = predict_placement_actions(history, current_regions)
107109

108-
print(f"Regions to deploy machines: {regions_to_deploy}")
109-
print(f"Regions to remove machines: {regions_to_remove}")
110+
logger.info(f"Regions to deploy machines: {regions_to_deploy}")
111+
logger.info(f"Regions to remove machines: {regions_to_remove}")
110112

111-
print("Updating placements...")
113+
logger.info("Updating placements...")
112114
update_placements(regions_to_deploy, regions_to_remove)
113-
print("Update complete.")
115+
logger.info("Update complete.")
116+
117+
result = {
118+
"current_traffic": current_data,
119+
"current_regions": current_regions,
120+
"regions_to_deploy": regions_to_deploy,
121+
"regions_to_remove": regions_to_remove,
122+
"update_status": "complete"
123+
}
124+
125+
return json.dumps(result)

Diff for: config.yaml

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
dry_run: true
2-
scale_up_threshold: 50
3-
scale_down_threshold: 30
4-
cooldown_period: 300 # Cooldown period in seconds between scaling actions in the same region
2+
scale_up_threshold: 80
3+
scale_down_threshold: 20
4+
cooldown_period: 60 # Cooldown period in seconds, between scaling actions in the same region
55
fly_app_name: "your-app-name"
66

77
allowed_regions:

Diff for: data/traffic_history.json

+34-33
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,42 @@
11
{
2-
"2024-10-01T16:03:42.269830": {
3-
"cdg": 26,
4-
"ams": 37,
5-
"sin": 47,
6-
"nrt": 74,
7-
"lhr": 51
2+
"2024-10-02T22:57:12.861698": {
3+
"cdg": 100,
4+
"ams": 26,
5+
"iad": 14,
6+
"sin": 87,
7+
"nrt": 73,
8+
"lhr": 45
89
},
9-
"2024-10-01T16:03:36.870259": {
10-
"cdg": 28,
11-
"ams": 42,
12-
"iad": 12,
13-
"sin": 80,
14-
"nrt": 91,
15-
"lhr": 67
10+
"2024-10-02T22:48:24.094983": {
11+
"cdg": 11,
12+
"ams": 40,
13+
"iad": 1,
14+
"sin": 83,
15+
"nrt": 80,
16+
"lhr": 84
1617
},
17-
"2024-10-01T15:47:08.624241": {
18-
"cdg": 51,
19-
"ams": 8,
20-
"iad": 21,
21-
"sin": 53,
22-
"nrt": 55,
23-
"lhr": 2
18+
"2024-10-02T22:48:23.176357": {
19+
"cdg": 2,
20+
"ams": 94,
21+
"iad": 6,
22+
"sin": 91,
23+
"nrt": 24,
24+
"lhr": 41
2425
},
25-
"2024-10-01T15:47:03.231474": {
26+
"2024-10-02T22:48:22.283724": {
2627
"cdg": 1,
27-
"ams": 83,
28-
"iad": 4,
29-
"sin": 45,
30-
"nrt": 57,
31-
"lhr": 12
28+
"ams": 8,
29+
"iad": 20,
30+
"sin": 21,
31+
"nrt": 33,
32+
"lhr": 93
3233
},
33-
"2024-10-01T15:46:57.836643": {
34-
"cdg": 2,
35-
"ams": 7,
36-
"iad": 1,
37-
"sin": 92,
38-
"nrt": 76,
39-
"lhr": 99
34+
"2024-10-02T22:48:21.246309": {
35+
"cdg": 15,
36+
"ams": 84,
37+
"iad": 7,
38+
"sin": 100,
39+
"nrt": 12,
40+
"lhr": 43
4041
}
4142
}

Diff for: main.py

+26-12
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
import os
2-
from automation.auto_placer import main
2+
import json
3+
from automation.auto_placer import main as auto_placer_main
34
from utils.fancy_logger import get_logger
45
from utils.metrics_fetcher import MetricsFetcher
56
import logging
67
import sys
78
import signal
8-
9+
from fastapi import FastAPI, Request
910
# Configure logging
1011
logging.basicConfig(
1112
level=logging.INFO,
@@ -17,14 +18,27 @@
1718
)
1819

1920
logger = get_logger(__name__)
21+
os.makedirs('data', exist_ok=True)
22+
23+
# def signal_handler(signum, frame):
24+
# logger.debug(f"Received signal {signum}. Shutting down gracefully...")
25+
# # Cleanup code here
26+
# sys.exit(0)
27+
28+
29+
app = FastAPI()
30+
@app.post("/test-auto-placer")
31+
async def auto_place(request: Request):
32+
data = await request.json()
33+
# Extract necessary information from the request
34+
# For example: app_name, api_token, configuration parameters
35+
result = json.loads(auto_placer_main())
36+
return {"status": "success", "details": result}
37+
2038

21-
def signal_handler(signum, frame):
22-
logger.debug(f"Received signal {signum}. Shutting down gracefully...")
23-
# Cleanup code here
24-
sys.exit(0)
2539

26-
if __name__ == "__main__":
27-
os.makedirs('data', exist_ok=True)
40+
# if __name__ == "__main__":
41+
# os.makedirs('data', exist_ok=True)
2842
# fetcher = MetricsFetcher()
2943

3044
# fly_app_name = os.environ.get('FLY_APP_NAME')
@@ -36,8 +50,8 @@ def signal_handler(signum, frame):
3650

3751
# print(traffic_data)
3852

39-
logger.info("Application started")
53+
# logger.info("Application started")
4054

41-
signal.signal(signal.SIGINT, signal_handler)
42-
signal.signal(signal.SIGTERM, signal_handler)
43-
main()
55+
# signal.signal(signal.SIGINT, signal_handler)
56+
# signal.signal(signal.SIGTERM, signal_handler)
57+
# main()

Diff for: prediction/placement_predictor.py

-3
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,6 @@
1616
EXCLUDED_REGIONS = config.get('excluded_regions', [])
1717
ALWAYS_RUNNING_REGIONS = config.get('always_running_regions', [])
1818

19-
print(f"SCALE_UP_THRESHOLD: {SCALE_UP_THRESHOLD}, Type: {type(SCALE_UP_THRESHOLD)}")
20-
print(f"SCALE_DOWN_THRESHOLD: {SCALE_DOWN_THRESHOLD}, Type: {type(SCALE_DOWN_THRESHOLD)}")
21-
2219
TRAFFIC_HISTORY_FILE = 'data/traffic_history.json'
2320

2421
def predict_placement_actions(history, current_regions):

Diff for: pyproject.toml

+10-2
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,21 @@ description = "An auto-placer for Fly.io deployments based on real-time traffic
55
authors = ["Your Name <[email protected]>"]
66
license = "MIT"
77
readme = "README.md"
8-
packages = [{ include = "fly_placer", from = "." }]
8+
packages = [
9+
{ include = "automation" },
10+
{ include = "utils" },
11+
{ include = "monitoring" },
12+
{ include = "prediction" }
13+
]
914

1015
[tool.poetry.dependencies]
11-
python = ">=3.8,<4.0"
16+
python = ">=3.9,<4.0"
1217
requests = "^2.27.1"
1318
python-dotenv = "^0.20.0"
1419
python-dateutil = "^2.9.0.post0"
20+
pyyaml = "^6.0.2"
21+
fastapi = {extras = ["standard"], version = "^0.115.0"}
22+
fastapi-limiter = "^0.1.6"
1523

1624
[tool.poetry.dev-dependencies]
1725
pytest = "^7.0"

0 commit comments

Comments
 (0)