Postgres persistance + job queue + api with sse #9

Merged
qpismont merged 8 commits from 1.3 into main 2026-10-26 21:19:32 +01:00
3 changed files with 5 additions and 35 deletions
Showing only changes of commit cedd052a4d - Show all commits

No files matched your search

+1
View File
1
@@ -39,6 +39,7 @@ steps:
environment: environment:
DATABASE_URL: postgresql://postgres:postgres@postgres:5432/steep DATABASE_URL: postgresql://postgres:postgres@postgres:5432/steep
commands: commands:
- bash scripts/migrate-apply.sh
- cargo test --workspace --all-targets -- --include-ignored - cargo test --workspace --all-targets -- --include-ignored
- name: container-build - name: container-build
+1 -1
View File
@@ -112,7 +112,7 @@ After changing a model in `crates/steep-server/src/schemas/`, generate a migrati
./scripts/migrate-generate.sh describe_change ./scripts/migrate-generate.sh describe_change
``` ```
Apply the pending migrations **before starting the service** — the server does not migrate at boot: Apply the pending migrations **before starting the service** — the server does not migrate at boot. The tests need the same schema: run this before `cargo test` too (CI does it as well):
```sh ```sh
./scripts/migrate-apply.sh ./scripts/migrate-apply.sh
+3 -34
View File
@@ -9,43 +9,12 @@ pub async fn open(url: &str) -> toasty::Result<Db> {
/// A connection for a test, on the database `DATABASE_URL` points to. /// A connection for a test, on the database `DATABASE_URL` points to.
/// ///
/// Every `#[tokio::test]` runs on its own runtime, and the connection tasks live on /// The schema must already be migrated: `scripts/migrate-apply.sh` does it, the same
/// the runtime that opened the pool: sharing one `Db` between tests would leave /// way it does for the server. Each test opens its own connection, because the
/// them with a pool whose runtime is gone. Each test therefore opens its own, and /// connection tasks live on the runtime of the test that opened them.
/// only the migrations are applied once.
#[cfg(test)] #[cfg(test)]
qpismont marked this conversation as resolved
Review

[bug] Au démarrage, tous les jobs Processing sont remis à Pending sans notion de propriétaire ou de lease. Si deux instances tournent simultanément, le démarrage de l'une peut réenfiler les jobs activement traités par l'autre, en plus de la course déjà présente dans le poller. La récupération après crash doit être limitée aux jobs dont le lease a expiré, et le traitement doit être atomiquement réservé.

**[bug]** Au démarrage, tous les jobs `Processing` sont remis à `Pending` sans notion de propriétaire ou de lease. Si deux instances tournent simultanément, le démarrage de l'une peut réenfiler les jobs activement traités par l'autre, en plus de la course déjà présente dans le poller. La récupération après crash doit être limitée aux jobs dont le lease a expiré, et le traitement doit être atomiquement réservé.
Review

[bug] Au démarrage, chaque instance remet à Pending tous les jobs Processing, y compris ceux qu’une autre instance est encore en train de traiter. Un redémarrage ou déploiement pendant une review peut donc la faire exécuter en double. La récupération doit distinguer les jobs réellement abandonnés de ceux détenus par des workers actifs.

**[bug]** Au démarrage, chaque instance remet à `Pending` tous les jobs `Processing`, y compris ceux qu’une autre instance est encore en train de traiter. Un redémarrage ou déploiement pendant une review peut donc la faire exécuter en double. La récupération doit distinguer les jobs réellement abandonnés de ceux détenus par des workers actifs.
pub(crate) async fn test_connect() -> Db { pub(crate) async fn test_connect() -> Db {
static MIGRATED: tokio::sync::OnceCell<()> = tokio::sync::OnceCell::const_new();
let url = std::env::var("DATABASE_URL").expect("DATABASE_URL must be set"); let url = std::env::var("DATABASE_URL").expect("DATABASE_URL must be set");
// The migrations run on a runtime of their own, which outlives the first test.
MIGRATED
.get_or_init(|| async {
let url = url.clone();
std::thread::spawn(move || {
tokio::runtime::Runtime::new()
.expect("migration runtime")
.block_on(async {
let migrations =
std::path::Path::new(env!("CARGO_MANIFEST_DIR")).join("toasty");
let config = toasty_cli::Config::new()
.migration(toasty_cli::MigrationConfig::new().path(migrations));
toasty_cli::ToastyCli::with_config(
open(&url).await.expect("open pool"),
config,
)
.parse_from(["toasty", "migration", "apply"])
.await
.expect("apply migrations");
});
})
.join()
.expect("migrations panicked");
})
.await;
open(&url).await.expect("connect to postgres") open(&url).await.expect("connect to postgres")
} }