Skip to content

Commit f76c702

Browse files
committed
lazy settings
1 parent aaa9779 commit f76c702

28 files changed

Lines changed: 707 additions & 482 deletions

docs/reference/task_plugin.md

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,20 +8,17 @@ and is registered via [TaskManager.with_plugin][fluid.scheduler.TaskManager.with
88

99
```python
1010
from fluid.scheduler import TaskScheduler, task_manager_fastapi
11-
from fluid.scheduler.db import TaskDbPlugin, with_task_history_router
11+
from fluid.scheduler.db import TaskDbPlugin
1212

1313
task_manager = TaskScheduler(...)
1414
task_manager.with_plugin(TaskDbPlugin(db))
1515
app = task_manager_fastapi(task_manager)
16-
with_task_history_router(app)
1716
```
1817

1918
::: fluid.scheduler.TaskManagerPlugin
2019

2120
::: fluid.scheduler.db.TaskDbPlugin
2221

23-
::: fluid.scheduler.db.with_task_history_router
24-
2522
## Accessing the plugin from a task
2623

2724
[get_db_plugin][fluid.scheduler.db.get_db_plugin] retrieves the registered
@@ -48,7 +45,7 @@ async def report(context: TaskRun) -> None:
4845

4946
The following models are used when querying task run history via
5047
[TaskDbPlugin.get_history][fluid.scheduler.db.TaskDbPlugin.get_history]
51-
or the HTTP endpoints added by [with_task_history_router][fluid.scheduler.db.with_task_history_router].
48+
or the HTTP endpoints.
5249

5350
They can be imported from `fluid.scheduler.db`:
5451

docs/tutorials/task_app.md

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -120,26 +120,24 @@ Register the plugin when building your task manager:
120120

121121
```python
122122
from fluid.scheduler import TaskScheduler, task_manager_fastapi
123-
from fluid.scheduler.db import TaskDbPlugin, with_task_history_router
123+
from fluid.scheduler.db import TaskDbPlugin
124124
from fluid.db import CrudDB
125125

126126
db = CrudDB.from_env()
127127
task_manager = TaskScheduler(...)
128128
task_manager.with_plugin(TaskDbPlugin(db))
129129
app = task_manager_fastapi(task_manager)
130-
with_task_history_router(app)
131130
```
132131

133132
The plugin creates a `fluid_tasks` table (configurable via `table_name`) and
134133
persists a row for each task run as it moves through its lifecycle states.
135134
Tasks tagged with `skip_db` are excluded from persistence.
136-
137-
`with_task_history_router` mounts a `/history` router on the app with two endpoints:
135+
The plugin mounts a `/tasks-history` router on the app with two endpoints:
138136

139137
| Method | Path | Description |
140138
|--------|------|-------------|
141-
| `GET` | `/history` | List task run history with optional filters |
142-
| `GET` | `/history/{run_id}` | Fetch a single task run by ID |
139+
| `GET` | `/tasks-history` | List task run history with optional filters |
140+
| `GET` | `/tasks-history/{run_id}` | Fetch a single task run by ID |
143141

144142
The list endpoint accepts the following query parameters:
145143

examples/__main__.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,3 @@
1-
import dotenv
2-
3-
dotenv.load_dotenv()
4-
51
from examples.cli import task_manager_cli # isort:skip # noqa: E402
62

73
task_manager_cli()

examples/cli.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
1+
import dotenv
2+
13
from fluid.scheduler.cli import TaskManagerCLI
24

5+
dotenv.load_dotenv()
6+
37
task_manager_cli = TaskManagerCLI(
48
"examples.tasks:task_app", lazy_subcommands={"db": "examples.db.cli:cli"}
59
)

examples/full_cli.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
from pathlib import Path
2+
3+
import dotenv
4+
5+
from fluid.db import CrudDB
6+
from fluid.db.cli import DbGroup
7+
from fluid.scheduler.cli import DEFAULT_COMMANDS, TaskManagerCLI
8+
from fluid.scheduler.db import TaskDbPlugin
9+
10+
dotenv.load_dotenv()
11+
12+
MIGRATIONS_PATH = Path(__file__).parent / "migrations"
13+
14+
15+
def create_cli() -> TaskManagerCLI:
16+
from examples.tasks import task_app
17+
18+
# create the database
19+
db = CrudDB.from_env(migration_path=MIGRATIONS_PATH, db_name="fluid_full_cli")
20+
# create the client
21+
task_manager_cli = TaskManagerCLI(
22+
task_app(plugins=[TaskDbPlugin(db)]),
23+
commands=list(DEFAULT_COMMANDS) + [DbGroup(db)],
24+
help="Task Manager CLI with db plugin",
25+
)
26+
return task_manager_cli
27+
28+
29+
if __name__ == "__main__":
30+
task_manager_cli = create_cli()
31+
task_manager_cli()

examples/simple.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
11
import asyncio
22

3-
from examples.tasks import task_scheduler
3+
import dotenv
4+
45
from fluid.utils import log
56

7+
dotenv.load_dotenv()
8+
69
if __name__ == "__main__":
10+
from examples.tasks import task_scheduler
11+
712
log.config()
813
asyncio.run(task_scheduler().run())

examples/simple_cli.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,13 @@
22

33
dotenv.load_dotenv()
44

5-
from fluid.scheduler.cli import TaskManagerCLI # isort:skip # noqa: E402
65

76
if __name__ == "__main__":
87
from examples.tasks import task_app
8+
from fluid.scheduler.cli import TaskManagerCLI
99

10-
task_manager_cli = TaskManagerCLI(task_app())
10+
task_manager_cli = TaskManagerCLI(
11+
task_app(),
12+
help="Simple Task Manager CLI with default commands",
13+
)
1114
task_manager_cli()

examples/simple_fastapi.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
1+
import dotenv
12
import uvicorn
23

3-
from examples.tasks import task_app
44
from fluid.utils import log
55

6+
dotenv.load_dotenv()
7+
68
if __name__ == "__main__":
9+
from examples.tasks import task_app
10+
711
log.config()
812
uvicorn.run(task_app())

examples/tasks/__init__.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,11 @@ def task_scheduler(
4848
return task_manager
4949

5050

51-
def task_app() -> FastAPI:
52-
return task_manager_fastapi(task_scheduler(), app=FastAPI(title="Task Manager API"))
51+
def task_app(plugins: Sequence[TaskManagerPlugin] | None = None) -> FastAPI:
52+
return task_manager_fastapi(
53+
task_scheduler(plugins=plugins),
54+
app=FastAPI(title="Task Manager API"),
55+
)
5356

5457

5558
class Sleep(BaseModel):

fluid/db/container.py

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,15 @@
33
from contextlib import asynccontextmanager
44
from dataclasses import dataclass, field
55
from pathlib import Path
6-
from typing import Any, AsyncIterator, Self
6+
from typing import AsyncIterator, Self
77

88
import sqlalchemy as sa
99
from sqlalchemy.engine import Engine, create_engine
1010
from sqlalchemy.engine.url import make_url
1111
from sqlalchemy.ext.asyncio import AsyncConnection, AsyncEngine, create_async_engine
1212

1313
from fluid import settings
14+
from fluid.utils.data import compact_dict
1415

1516
from .migration import Migration
1617

@@ -31,30 +32,50 @@ class Database:
3132
Currently, only `postgresql+asyncpg` is supported, but other databases may
3233
be supported in the future.
3334
"""
34-
echo: bool = settings.DBECHO
35+
echo: bool = field(default_factory=lambda: settings.DBECHO)
3536
"""Echo SQL queries to stdout
3637
3738
It defaults to the `DBECHO` setting in the settings module
3839
"""
39-
pool_size: int = settings.DBPOOL_MAX_SIZE
40-
max_overflow: int = settings.DBPOOL_MAX_OVERFLOW
40+
pool_size: int = field(default_factory=lambda: settings.DBPOOL_MAX_SIZE)
41+
max_overflow: int = field(default_factory=lambda: settings.DBPOOL_MAX_OVERFLOW)
4142
metadata: sa.MetaData = field(default_factory=sa.MetaData)
4243
migration_path: str | Path = ""
4344
"""Path to the directory containing migration files. If empty, migrations will
4445
be stored in the default location `migrations` in the current working directory.
4546
"""
46-
app_name: str = settings.APP_NAME
47+
app_name: str = field(default_factory=lambda: settings.APP_NAME)
4748
_engine: AsyncEngine | None = None
4849

4950
@classmethod
5051
def from_env(
5152
cls,
5253
*,
53-
dsn: str = settings.DATABASE,
54-
schema: str | None = settings.DATABASE_SCHEMA,
55-
**kwargs: Any,
54+
dsn: str | None = None,
55+
schema: str | None = None,
56+
migration_path: str | Path | None = None,
57+
app_name: str | None = None,
58+
max_overflow: int | None = None,
59+
pool_size: int | None = None,
60+
db_name: str | None = None,
5661
) -> Self:
5762
"""Create a new database container from environment variables as defaults"""
63+
if dsn is None:
64+
dsn = settings.DATABASE
65+
if schema is None:
66+
schema = settings.DATABASE_SCHEMA
67+
kwargs = compact_dict(
68+
migration_path=migration_path,
69+
app_name=app_name,
70+
max_overflow=max_overflow,
71+
pool_size=pool_size,
72+
)
73+
if db_name:
74+
dsn = (
75+
make_url(dsn)
76+
.set(database=db_name)
77+
.render_as_string(hide_password=False)
78+
)
5879
return cls(dsn=dsn, metadata=sa.MetaData(schema=schema), **kwargs)
5980

6081
@property

0 commit comments

Comments
 (0)