feat: add initial postgres

Signed-off-by: kjuulh <contact@kjuulh.io>
This commit is contained in:
2026-01-18 17:23:09 +01:00
parent 1904654a06
commit e0d6172e21
7 changed files with 1406 additions and 76 deletions

1351
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -24,6 +24,19 @@ serde_json = "1.0.148"
sha2 = "0.10.9" sha2 = "0.10.9"
tokio-util = "0.7.18" tokio-util = "0.7.18"
sqlx = { version = "0.8.6", optional = true, features = [
"chrono",
"json",
"postgres",
"runtime-tokio",
"uuid",
] }
[dev-dependencies] [dev-dependencies]
insta = "1.46.0" insta = "1.46.0"
tracing-test = { version = "0.2.5", features = ["no-env-filter"] } tracing-test = { version = "0.2.5", features = ["no-env-filter"] }
[features]
default = []
postgres = ["dep:sqlx"]

View File

@@ -0,0 +1 @@
-- Add migration script here

View File

@@ -10,6 +10,9 @@ use crate::{
pub mod in_process; pub mod in_process;
#[cfg(feature = "postgres")]
pub mod postgres;
#[derive(Clone)] #[derive(Clone)]
pub struct BackingStore<T: Specification, TStore: BackingStoreEdge<T>> { pub struct BackingStore<T: Specification, TStore: BackingStoreEdge<T>> {
inner: TStore, inner: TStore,
@@ -42,6 +45,16 @@ impl<T: Specification> BackingStore<T, BackingStoreInProcess<T>> {
} }
} }
#[cfg(feature = "postgres")]
impl<T: Specification> BackingStore<T, postgres::BackingStorePostgres<T>> {
pub fn postgres(database_url: &str) -> Self {
Self {
inner: postgres::BackingStorePostgres::new(database_url),
_marker: PhantomData,
}
}
}
pub trait BackingStoreEdge<T: Specification>: Send + Sync + Clone { pub trait BackingStoreEdge<T: Specification>: Send + Sync + Clone {
fn get_owned_and_potential_leases( fn get_owned_and_potential_leases(
&self, &self,

View File

@@ -0,0 +1,72 @@
use std::marker::PhantomData;
use anyhow::Context;
use sqlx::PgPool;
use crate::{Specification, stores::BackingStoreEdge};
#[derive(Clone)]
pub struct BackingStorePostgres<T: Specification> {
pool: PgPool,
_marker: PhantomData<T>,
}
impl<T: Specification> BackingStorePostgres<T> {
pub(crate) async fn new(database_url: &str) -> anyhow::Result<Self> {
let pool = sqlx::PgPool::connect(database_url)
.await
.context("failed to connect to database")?;
sqlx::migrate!("migrations/postgres/")
.run(&pool)
.await
.context("failed to migrate")?;
Ok(Self {
_marker: PhantomData,
pool,
})
}
}
impl<T: Specification> BackingStoreEdge<T> for BackingStorePostgres<T> {
async fn get_owned_and_potential_leases(
&self,
worker_id: &uuid::Uuid,
) -> anyhow::Result<Vec<crate::manifests::ManifestState<T>>> {
todo!()
}
async fn get_manifests(&self) -> anyhow::Result<Vec<crate::manifests::ManifestState<T>>> {
todo!()
}
async fn get(&self, name: &str) -> anyhow::Result<Option<crate::manifests::ManifestState<T>>> {
todo!()
}
async fn update_lease(
&self,
manifest_state: &crate::manifests::ManifestState<T>,
) -> anyhow::Result<()> {
todo!()
}
async fn acquire_lease(
&self,
manifest_state: &crate::manifests::ManifestState<T>,
worker_id: &crate::manifests::WorkerId,
) -> anyhow::Result<()> {
todo!()
}
async fn upsert_manifest(&self, manifest: crate::manifests::Manifest<T>) -> anyhow::Result<()> {
todo!()
}
async fn update_state(
&self,
manifest: &crate::manifests::ManifestState<T>,
) -> anyhow::Result<()> {
todo!()
}
}

View File

@@ -8,3 +8,15 @@ run = "cargo nextest run"
[tasks.example] [tasks.example]
alias = "e" alias = "e"
run = "cargo run --bin kubernetes-like" run = "cargo run --bin kubernetes-like"
[tasks."example:postgres"]
run = "cargo run --bin postgres-backed"
[tasks."local:up"]
run = "docker compose -f ./templates/docker/docker-compose.yml up -d --remove-orphans --wait"
[tasks."local:down"]
run = "docker compose -f ./templates/docker/docker-compose.yml down"
[tasks."local:logs"]
run = "docker compose -f ./templates/docker/docker-compose.yml logs -f --tail=500"

View File

@@ -0,0 +1,20 @@
services:
postgres:
image: postgres:18
environment:
POSTGRES_USER: devuser
POSTGRES_PASSWORD: devpassword
POSTGRES_DB: dev
ports:
- "5432:5432"
healthcheck:
test: ["CMD-SHELL", "pg_isready -U devuser -d dev"]
interval: 5s
timeout: 5s
retries: 5
volumes:
- ${PWD}/fs/volumes/postgres/docker-entrypoint-initdb.d:/docker-entrypoint-initdb.d
command:
- "postgres"
- "-c"
- "wal_level=logical" #required for MaterializedPostgreSQL