Skip to content

Commit 5a6cce8

Browse files
committed
Add Redis job store service
Introduce a Redis-backed job store and enable Redis in deployment. Adds a Redis service to docker-compose and exposes REDIS_URL to the app, adds redis dependency to requirements, and adds redis_url to app settings. Implements RedisJobStore (with 24h TTL) and updates get_job_store to prefer Redis when redis_url is configured. Also bumps default_max_cells to 1,000,000.
1 parent 1ac4562 commit 5a6cce8

4 files changed

Lines changed: 36 additions & 2 deletions

File tree

deploy/compose/base.yml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,19 @@ services:
44
context: .
55
dockerfile: deploy/Dockerfile
66
restart: always
7+
environment:
8+
REDIS_URL: redis://redis:6379
79
volumes:
810
- ./img_logs:/shared
911
networks:
1012
- internal_geospatial_net # Internal network to see Titiler
1113
- default # External access to reach S3 and serve the frontend
14+
redis:
15+
image: redis:7-alpine
16+
restart: always
17+
networks:
18+
- internal_geospatial_net
19+
1220
titiler:
1321
image: ghcr.io/developmentseed/titiler:latest
1422
restart: always

deploy/requirements/base.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,6 @@ PyYAML==6.0.3
2828

2929
# Observability
3030
sentry-sdk==2.55.0
31+
32+
# Job store
33+
redis>=5.0

timeseries/app/config.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from functools import lru_cache
22
from logging.config import dictConfig
33
from pathlib import Path
4-
from typing import List, Tuple, Type
4+
from typing import List, Optional, Tuple, Type
55
from pydantic import BaseModel
66
from pydantic_settings import (
77
BaseSettings,
@@ -28,8 +28,9 @@ class Settings(BaseSettings):
2828
name: str = "SKOPE API Services (development)"
2929
base_uri: str = "timeseries"
3030
max_processing_time: int = 15000 # in milliseconds
31-
default_max_cells:int = 500000 # max number of cells to extract from data cubes
31+
default_max_cells:int = 1000000 # max number of cells to extract from data cubes
3232
store: Store
33+
redis_url: Optional[str] = None
3334
sentry_dsn: str = "https://9b9dc2f60562380edeb675c39fe1c896@sentry.comses.net/4"
3435
tile_server_url: str
3536
storage_base_url: str

timeseries/app/store/jobs.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import time
33
import os
44
import json
5+
import redis as redis_lib
56

67
_JOBS_DIR = "/tmp/skope_jobs"
78

@@ -47,5 +48,26 @@ def get_job_status(self, job_id: str) -> dict | None:
4748
with open(file_path, "r") as f:
4849
return json.load(f)
4950

51+
_JOB_TTL_SECONDS = 86400 # 24 hours — matches cleanup_stale_jobs default
52+
53+
54+
class RedisJobStore(JobStore):
55+
def __init__(self, redis_url: str):
56+
self._client = redis_lib.Redis.from_url(redis_url, decode_responses=True)
57+
58+
def update_job(self, job_id: str, status_data: dict) -> None:
59+
self._client.set(f"job:{job_id}", json.dumps(status_data), ex=_JOB_TTL_SECONDS)
60+
61+
def get_job_status(self, job_id: str) -> dict | None:
62+
raw = self._client.get(f"job:{job_id}")
63+
if raw is None:
64+
return None
65+
return json.loads(raw)
66+
67+
5068
def get_job_store() -> JobStore:
69+
from app.config import get_settings
70+
settings = get_settings()
71+
if settings.redis_url:
72+
return RedisJobStore(settings.redis_url)
5173
return FileSystemJobStore()

0 commit comments

Comments
 (0)