From a9ca410d08f326737199fdf73e3e357880c180f7 Mon Sep 17 00:00:00 2001
From: Michael Plunkett <5885605+michplunkett@users.noreply.github.com>
Date: Mon, 3 Mar 2025 13:20:11 -0600
Subject: [PATCH] Move `alembic.ini` to `migrations` directory (#66)
---
alembic.ini => app/migrations/alembic.ini | 6 +-
app/tests/web/test_main.py | 20 +++-
app/web/events.py | 114 +++++++++++++++++-----
docker/web/Dockerfile | 1 -
docker/worker/Dockerfile | 1 -
5 files changed, 110 insertions(+), 32 deletions(-)
rename alembic.ini => app/migrations/alembic.ini (95%)
diff --git a/alembic.ini b/app/migrations/alembic.ini
similarity index 95%
rename from alembic.ini
rename to app/migrations/alembic.ini
index 30d7030..fa1578b 100644
--- a/alembic.ini
+++ b/app/migrations/alembic.ini
@@ -2,7 +2,7 @@
[alembic]
# path to migration scripts
-script_location = app/migrations
+script_location = ./app/migrations
# template used to generate migration file names; The default value is %%(rev)s_%%(slug)s
# Uncomment the line below if you want the files to be prepended with date and time
@@ -10,10 +10,6 @@ script_location = app/migrations
# for all available tokens
# file_template = %%(year)d_%%(month).2d_%%(day).2d_%%(hour).2d%%(minute).2d-%%(rev)s_%%(slug)s
-# sys.path path, will be prepended to sys.path if present.
-# defaults to the current working directory.
-prepend_sys_path = .
-
# timezone to use when rendering the date within the migration file
# as well as the filename.
# If specified, requires the python-dateutil library that can be
diff --git a/app/tests/web/test_main.py b/app/tests/web/test_main.py
index 0dbd5fa..eb985a8 100644
--- a/app/tests/web/test_main.py
+++ b/app/tests/web/test_main.py
@@ -18,8 +18,24 @@ def test_lifespan(app):
def test_alembic(db_session):
- alembic.config.main(argv=["--raiseerr", "upgrade", "head"])
- alembic.config.main(argv=["--raiseerr", "downgrade", "base"])
+ alembic.config.main(
+ argv=[
+ "-c",
+ "./app/migrations/alembic.ini",
+ "--raiseerr",
+ "upgrade",
+ "head",
+ ]
+ )
+ alembic.config.main(
+ argv=[
+ "-c",
+ "./app/migrations/alembic.ini",
+ "--raiseerr",
+ "downgrade",
+ "base",
+ ]
+ )
@patch(
diff --git a/app/web/events.py b/app/web/events.py
index fa15614..17a24b9 100644
--- a/app/web/events.py
+++ b/app/web/events.py
@@ -38,9 +38,22 @@ async def lifespan(app: FastAPI):
# STARTUP
engine = make_engine(get_settings().DATABASE_PATH)
models.Base.metadata.create_all(bind=engine)
- alembic.config.main(prog="alembic", argv=['--raiseerr', 'upgrade', 'head'])
+ alembic.config.main(
+ prog="alembic",
+ argv=[
+ "-c",
+ "./app/migrations/alembic.ini",
+ "--raiseerr",
+ "upgrade",
+ "head",
+ ],
+ )
logging.getLogger("uvicorn.access").disabled = True # loguru
- asyncio.create_task(redis_subscribe_worker_exceptions(get_settings().REDIS_EXCEPTIONS_CHANNEL))
+ asyncio.create_task(
+ redis_subscribe_worker_exceptions(
+ get_settings().REDIS_EXCEPTIONS_CHANNEL
+ )
+ )
asyncio.create_task(repeat_measure_regular_metrics())
with get_db() as db:
crud.upsert_user_groups(db)
@@ -71,41 +84,74 @@ async def lifespan(app: FastAPI):
# CRON JOBS
-@repeat_every(seconds=get_settings().REPEAT_COUNT_METRICS_SECONDS, on_exception=increase_exceptions_counter)
+@repeat_every(
+ seconds=get_settings().REPEAT_COUNT_METRICS_SECONDS,
+ on_exception=increase_exceptions_counter,
+)
async def repeat_measure_regular_metrics():
- await measure_regular_metrics(get_settings().DATABASE_PATH, get_settings().REPEAT_COUNT_METRICS_SECONDS)
+ await measure_regular_metrics(
+ get_settings().DATABASE_PATH,
+ get_settings().REPEAT_COUNT_METRICS_SECONDS,
+ )
-@repeat_every(seconds=60, wait_first=120, on_exception=increase_exceptions_counter)
+@repeat_every(
+ seconds=60, wait_first=120, on_exception=increase_exceptions_counter
+)
async def archive_hourly_sheets_cronjob():
await archive_sheets_cronjob("hourly", 60, datetime.datetime.now().minute)
-@repeat_every(seconds=3600, wait_first=120, on_exception=increase_exceptions_counter)
+@repeat_every(
+ seconds=3600, wait_first=120, on_exception=increase_exceptions_counter
+)
async def archive_daily_sheets_cronjob():
await archive_sheets_cronjob("daily", 24, datetime.datetime.now().hour)
-async def archive_sheets_cronjob(frequency: str, interval: int, current_time_unit: int):
+async def archive_sheets_cronjob(
+ frequency: str, interval: int, current_time_unit: int
+):
triggered_jobs = []
async with get_db_async() as db:
- sheets = await crud.get_sheets_by_id_hash(db, frequency, interval, current_time_unit)
+ sheets = await crud.get_sheets_by_id_hash(
+ db, frequency, str(interval), current_time_unit
+ )
for s in sheets:
group_queue = await crud.get_group_priority_async(db, s.group_id)
- task = celery.signature("create_sheet_task", args=[schemas.SubmitSheet(sheet_id=s.id, author_id=s.author_id, group_id=s.group_id).model_dump_json()]).apply_async(**group_queue)
+ task = celery.signature(
+ "create_sheet_task",
+ args=[
+ schemas.SubmitSheet(
+ sheet_id=s.id,
+ author_id=s.author_id,
+ group_id=s.group_id,
+ ).model_dump_json()
+ ],
+ ).apply_async(**group_queue)
triggered_jobs.append({"sheet_id": s.id, "task_id": task.id})
- logger.debug(f"[CRON {frequency.upper()}:{current_time_unit}] Triggered {len(triggered_jobs)} sheet tasks: {triggered_jobs}")
+ logger.debug(
+ f"[CRON {frequency.upper()}:{current_time_unit}] Triggered {len(triggered_jobs)} sheet tasks: {triggered_jobs}"
+ )
# TODO: on exception should logerror but also prometheus counter
-DELETE_WINDOW = get_settings().DELETE_SCHEDULED_ARCHIVES_CHECK_EVERY_N_DAYS * 24 * 60 * 60
+DELETE_WINDOW = (
+ get_settings().DELETE_SCHEDULED_ARCHIVES_CHECK_EVERY_N_DAYS * 24 * 60 * 60
+)
-@repeat_every(seconds=DELETE_WINDOW, wait_first=180, on_exception=increase_exceptions_counter)
+@repeat_every(
+ seconds=DELETE_WINDOW,
+ wait_first=180,
+ on_exception=increase_exceptions_counter,
+)
async def notify_about_expired_archives():
- notify_from = datetime.datetime.now() + datetime.timedelta(days=get_settings().DELETE_SCHEDULED_ARCHIVES_CHECK_EVERY_N_DAYS)
+ notify_from = datetime.datetime.now() + datetime.timedelta(
+ days=get_settings().DELETE_SCHEDULED_ARCHIVES_CHECK_EVERY_N_DAYS
+ )
async with get_db_async() as db:
scheduled_deletions = await crud.find_by_store_until(db, notify_from)
@@ -117,7 +163,12 @@ async def notify_about_expired_archives():
fastmail = FastMail(get_settings().MAIL_CONFIG)
# notify users
for email in user_archives:
- list_of_archives = "\n".join([f'{a.url}, {a.id}, {a.store_until.isoformat()}
' for a in user_archives[email]])
+ list_of_archives = "\n".join(
+ [
+ f"{a.url}, {a.id}, {a.store_until.isoformat()}
"
+ for a in user_archives[email]
+ ]
+ )
# TODO: how can users download them in bulk?
message = MessageSchema(
subject="Auto Archiver: Archives Scheduled for Deletion",
@@ -137,16 +188,23 @@ async def notify_about_expired_archives():