Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions vicky/migrations/2026-07-09-081408-0000_task_groups/down.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
-- This file should undo anything in `up.sql`



ALTER TABLE tasks
ADD COLUMN "group" VARCHAR;

UPDATE tasks
SET "group" = tg.name
FROM task_groups tg
WHERE group_id = tg.id;

ALTER TABLE tasks
DROP COLUMN group_id;

DROP TABLE task_groups;
25 changes: 25 additions & 0 deletions vicky/migrations/2026-07-09-081408-0000_task_groups/up.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
-- Your SQL goes here

create table task_groups
(
id uuid default uuid_generate_v4() not null primary key,
name varchar not null,
created_at timestamp with time zone default now() not null
);

INSERT INTO task_groups(name)
SELECT DISTINCT "group" from tasks WHERE "group" IS NOT NULL;

ALTER TABLE tasks
ADD COLUMN "group_id" uuid;

ALTER TABLE tasks
ADD CONSTRAINT fk_task FOREIGN KEY(group_id) REFERENCES task_groups(id);


UPDATE tasks t
SET group_id = tg.id
FROM task_groups tg WHERE t.group = tg.name;

ALTER TABLE tasks
DROP COLUMN "group";
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
-- This file should undo anything in `up.sql`

alter table tasks
alter column group_id drop not null;
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
-- Your SQL goes here


INSERT INTO task_groups(name)
SELECT DISTINCT CONCAT('Group of ', "display_name") as "group" from tasks WHERE "group_id" IS NULL;

UPDATE tasks t
SET group_id = tg.id
FROM task_groups tg WHERE CONCAT('Group of ', t."display_name") = tg.name;


alter table tasks
alter column group_id set not null;

11 changes: 11 additions & 0 deletions vicky/src/bin/vicky/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use crate::locks::{
locks_get_active, locks_get_detailed_poisoned, locks_get_poisoned, locks_unlock,
};
use crate::startup::Result;
use crate::task_groups::{task_groups_add, task_groups_count, task_groups_get, task_groups_get_specific};
use crate::tasks::{
tasks_add, tasks_cancel, tasks_claim, tasks_confirm, tasks_count, tasks_download_logs,
tasks_finish, tasks_get, tasks_get_logs, tasks_get_specific, tasks_heartbeat, tasks_put_logs,
Expand Down Expand Up @@ -36,6 +37,7 @@ mod events;
mod locks;
mod startup;
mod tasks;
mod task_groups;
mod user;
mod webconfig;

Expand Down Expand Up @@ -215,6 +217,15 @@ async fn build_web_api(
tasks_cancel
],
)
.mount(
"/api/v1/task-groups",
routes![
task_groups_count,
task_groups_get,
task_groups_get_specific,
task_groups_add,
],
)
.mount(
"/api/v1/locks",
routes![
Expand Down
80 changes: 80 additions & 0 deletions vicky/src/bin/vicky/task_groups.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
use rocket::{State, post};
use rocket::{get, serde::json::Json};
use serde::{Deserialize, Serialize};
use tokio::sync::broadcast;
use uuid::Uuid;
use vickylib::database::entities::task_group::TaskGroup;
use vickylib::database::entities::Database;
use vickylib::query::FilterParams;
use vickylib::vicky::events::GlobalEvent;

use crate::auth::{AnyAuthGuard, MachineGuard};
use crate::errors::AppError;

#[derive(Debug, PartialEq, Serialize, Deserialize)]
pub struct RoTaskGroupNew {
name: String,
}
#[derive(Debug, PartialEq, Serialize, Deserialize)]
pub struct Count {
count: i64,
}

#[derive(Debug, PartialEq, Serialize, Deserialize)]
pub struct Empty {
}

#[get("/count")]
pub async fn task_groups_count(
db: Database,
_auth: AnyAuthGuard,
) -> Result<Json<Count>, AppError> {
let task_group_count = db.count_all_task_groups().await?;
let c: Count = Count { count: task_group_count };
Ok(Json(c))
}

#[get("/?<filter_params..>")]
pub async fn task_groups_get(
db: Database,
_auth: AnyAuthGuard,
filter_params: Option<FilterParams>,
) -> Result<Json<Vec<TaskGroup>>, AppError> {
let task_group: Vec<TaskGroup> = db
.get_task_groups_filtered(filter_params)
.await?;
Ok(Json(task_group))
}

#[get("/<id>")]
pub async fn task_groups_get_specific(
id: Uuid,
db: Database,
_auth: AnyAuthGuard,
) -> Result<Json<Option<TaskGroup>>, AppError> {
let tasks: Option<TaskGroup> = db.get_task_group(id).await?;
Ok(Json(tasks))
}


#[post("/", data = "<task_group>")]
pub async fn task_groups_add(
task_group: Json<RoTaskGroupNew>,
db: Database,
_machine: MachineGuard,
global_events: &State<broadcast::Sender<GlobalEvent>>,
) -> Result<Json<Empty>, AppError> {


let task_group_ro = task_group.into_inner();

let db_task_group = TaskGroup::new(
task_group_ro.name,
);

db.put_task_groups(db_task_group).await?;

global_events.send(GlobalEvent::TaskGroupAdd)?;

Ok(Json(Empty{}))
}
6 changes: 4 additions & 2 deletions vicky/src/bin/vicky/tasks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ pub struct RoTaskNew {
flake_ref: FlakeRef,
locks: Vec<Lock>,
features: HashSet<String>,
group: Option<String>,
group_id: Uuid,
}

#[derive(Debug, PartialEq, Serialize, Deserialize)]
Expand Down Expand Up @@ -341,7 +341,7 @@ pub async fn tasks_add(
.flake_args(task.flake_ref.args)
.locks(task.locks)
.requires_features(task.features)
.maybe_group(task.group)
.group_id(task.group_id)
.build();

let Ok(task) = task else {
Expand Down Expand Up @@ -436,6 +436,7 @@ mod tests {
.display_name("Test 1")
.read_lock("mauz")
.write_lock("mauz")
.group_id(uuid::uuid!("00000000-0000-0000-0000-000000000000"))
.build();
assert!(task.is_err());
}
Expand All @@ -447,6 +448,7 @@ mod tests {
.read_lock("mauz")
.read_lock("mauz")
.write_lock("delete_everything")
.group_id(uuid::uuid!("00000000-0000-0000-0000-000000000000"))
.build();
assert!(task.is_ok())
}
Expand Down
21 changes: 20 additions & 1 deletion vicky/src/lib/database/entities/mod.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
pub mod lock;
pub mod task;
pub mod task_group;
pub mod user;

use crate::database::entities::lock::PoisonedLock;
use crate::database::entities::{lock::PoisonedLock, task_group::TaskGroup};
use crate::database::entities::lock::db_impl::LockDatabase;
use crate::database::entities::task::TaskStatus;
use crate::database::entities::task::db_impl::TaskDatabase;
use crate::database::entities::task_group::db_impl::TaskGroupDatabase;
use crate::database::entities::user::User;
use crate::database::entities::user::db_impl::UserDatabase;
use crate::errors::VickyError;
Expand Down Expand Up @@ -53,6 +55,23 @@ impl Database {
pub async fn timeout_task(&self, task_id: Uuid) -> Result<usize, VickyError>;
}

#[await(false)]
#[expr(self.run(move |conn| $).await)]
#[through(TaskGroupDatabase)]
to conn {
pub async fn count_all_task_groups(
&self,
) -> Result<i64, VickyError>;
pub async fn get_task_groups(&self) -> Result<Vec<TaskGroup>, VickyError>;
pub async fn get_task_groups_filtered<F: Into<FilterParams> + Send + 'static>(
&self,
filters: F,
) -> Result<Vec<TaskGroup>, VickyError>;
pub async fn get_task_group(&self, task_group_id: Uuid) -> Result<Option<TaskGroup>, VickyError>;
pub async fn put_task_groups(&self, task_group: TaskGroup) -> Result<usize, VickyError>;
}


#[await(false)]
#[expr(self.run(move |conn| $).await)]
#[through(LockDatabase)]
Expand Down
16 changes: 8 additions & 8 deletions vicky/src/lib/database/entities/task.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ pub struct Task {
#[serde(with = "ts_seconds_option")]
pub last_heartbeat: Option<DateTime<Utc>>,

pub group: Option<String>,
pub group_id: Uuid,
}

impl Task {
Expand Down Expand Up @@ -222,7 +222,7 @@ impl From<(DbTask, Vec<DbLock>)> for Task {
claimed_at: task.claimed_at,
finished_at: task.finished_at,
last_heartbeat: task.last_heartbeat,
group: task.group,
group_id: task.group_id,
}
}
}
Expand Down Expand Up @@ -316,7 +316,7 @@ pub mod db_impl {

pub finished_at: Option<DateTime<Utc>>,
pub last_heartbeat: Option<DateTime<Utc>>,
pub group: Option<String>,
pub group_id: Uuid,
}

pub const STATE_NEEDS_USER_VALIDATION_STR: &str = "NEEDS_USER_VALIDATION";
Expand Down Expand Up @@ -374,7 +374,7 @@ pub mod db_impl {
claimed_at: task.claimed_at,
finished_at: task.finished_at,
last_heartbeat: task.last_heartbeat,
group: task.group,
group_id: task.group_id,
}
}
}
Expand Down Expand Up @@ -419,8 +419,8 @@ pub mod db_impl {
tasks_count_b = tasks_count_b.filter(tasks::status.eq(task_status))
}

if let Some(group) = filters.group {
tasks_count_b = tasks_count_b.filter(tasks::group.eq(group))
if let Some(group_id) = filters.group_id {
tasks_count_b = tasks_count_b.filter(tasks::group_id.eq(group_id))
}

let tasks_count: i64 = tasks_count_b.count().first(self)?;
Expand All @@ -447,8 +447,8 @@ pub mod db_impl {
if let Some(r_offset) = filters.offset {
db_tasks_build = db_tasks_build.offset(r_offset)
}
if let Some(group) = filters.group {
db_tasks_build = db_tasks_build.filter(tasks::group.eq(group))
if let Some(group_id) = filters.group_id {
db_tasks_build = db_tasks_build.filter(tasks::group_id.eq(group_id))
}

let db_tasks = db_tasks_build
Expand Down
Loading
Loading