resuming suspended flows as owner is now through flow id

This commit is contained in:
Ruben Fiszel
2022-12-24 09:16:30 +01:00
parent fcb466812a
commit cd435fa07c
7 changed files with 94 additions and 11 deletions
+38
View File
@@ -593,6 +593,44 @@
},
"query": "UPDATE queue SET logs = $1 WHERE id = $2"
},
"1c28baaadd7d0c86a92bf9880a4ea33457bf8cff669e983431f1fd26ff275f83": {
"describe": {
"columns": [
{
"name": "id",
"ordinal": 0,
"type_info": "Uuid"
},
{
"name": "flow_status",
"ordinal": 1,
"type_info": "Jsonb"
},
{
"name": "suspend",
"ordinal": 2,
"type_info": "Int4"
},
{
"name": "script_path",
"ordinal": 3,
"type_info": "Varchar"
}
],
"nullable": [
false,
true,
false,
true
],
"parameters": {
"Left": [
"Uuid"
]
}
},
"query": "\n SELECT id, flow_status, suspend, script_path\n FROM queue\n WHERE id = $1\n "
},
"1e35c39bc786d638252e5483ca4efae9a041f7e845341f8bfd715ddd9e899499": {
"describe": {
"columns": [
+1 -1
View File
@@ -3176,7 +3176,7 @@ paths:
/w/{workspace}/jobs/flow/resume/{id}:
post:
summary: resume a job for a suspended flow as an owner
operationId: resumeSuspendedJobAsOwner
operationId: resumeSuspendedFlowAsOwner
tags:
- job
parameters:
+40 -4
View File
@@ -406,6 +406,7 @@ async fn list_jobs(
"false as is_skipped",
"email",
"visible_to_owner",
"suspend",
],
);
let sqlc = list_completed_jobs_query(
@@ -440,6 +441,7 @@ async fn list_jobs(
"is_skipped",
"email",
"visible_to_owner",
"null as suspend",
],
);
let sql = format!(
@@ -458,13 +460,13 @@ async fn list_jobs(
pub async fn resume_suspended_flow_as_owner(
authed: Authed,
Extension(db): Extension<DB>,
Path((w_id, job_id)): Path<(String, Uuid)>,
Path((w_id, flow_id)): Path<(String, Uuid)>,
QueryOrBody(value): QueryOrBody<serde_json::Value>,
) -> error::Result<StatusCode> {
let value = value.unwrap_or(serde_json::Value::Null);
let mut tx = db.begin().await?;
let flow = get_suspended_flow_info(job_id, &mut tx).await?;
let (flow, job_id) = get_suspended_flow_info(flow_id, &mut tx).await?;
if !authed.is_admin {
require_owner_of_path(
@@ -502,7 +504,7 @@ pub async fn resume_suspended_job(
}
mac.verify_slice(hex::decode(secret)?.as_ref())
.map_err(|_| anyhow::anyhow!("Invalid signature"))?;
let flow = get_suspended_flow_info(job_id, &mut tx).await?;
let flow = get_suspended_prent_flow_info(job_id, &mut tx).await?;
let exists = sqlx::query_scalar!(
r#"
@@ -593,7 +595,7 @@ struct FlowInfo {
script_path: Option<String>,
}
async fn get_suspended_flow_info<'c>(
async fn get_suspended_prent_flow_info<'c>(
job_id: Uuid,
tx: &mut Transaction<'c, Postgres>,
) -> error::Result<FlowInfo> {
@@ -613,6 +615,38 @@ async fn get_suspended_flow_info<'c>(
Ok(flow)
}
async fn get_suspended_flow_info<'c>(
job_id: Uuid,
tx: &mut Transaction<'c, Postgres>,
) -> error::Result<(FlowInfo, Uuid)> {
let flow = sqlx::query_as!(
FlowInfo,
r#"
SELECT id, flow_status, suspend, script_path
FROM queue
WHERE id = $1
"#,
job_id,
)
.fetch_optional(tx)
.await?
.ok_or_else(|| anyhow::anyhow!("parent flow job not found"))?;
let job_id = flow
.flow_status
.as_ref()
.and_then(|v| serde_json::from_value::<FlowStatus>(v.clone()).ok())
.and_then(|s| match s.modules.get(s.step as usize) {
Some(FlowStatusModule::WaitingForEvents { job, .. }) => Some(job.to_owned()),
_ => None,
});
if let Some(job_id) = job_id {
Ok((flow, job_id))
} else {
Err(anyhow::anyhow!("the flow is not in a suspended state anymore").into())
}
}
pub async fn cancel_suspended_job(
/* unauthed */
Extension(db): Extension<DB>,
@@ -885,6 +919,7 @@ struct UnifiedJob {
is_skipped: bool,
email: String,
visible_to_owner: bool,
suspend: Option<i32>,
}
impl From<UnifiedJob> for Job {
@@ -950,6 +985,7 @@ impl From<UnifiedJob> for Job {
pre_run_error: None,
email: uj.email,
visible_to_owner: uj.visible_to_owner,
suspend: uj.suspend,
}),
t => panic!("job type {} not valid", t),
}
+1
View File
@@ -598,6 +598,7 @@ pub struct QueuedJob {
pub pre_run_error: Option<String>,
pub email: String,
pub visible_to_owner: bool,
pub suspend: Option<i32>,
}
impl QueuedJob {
@@ -97,7 +97,7 @@
<div class="flex flex-row justify-between w-full items-center gap-x-2">
<button
on:click={() => dispatch('close')}
class="hover:bg-gray-200 bg-gray-100 rounded-full w-8 h-8 flex items-center justify-center transition-all"
class="hover:bg-gray-200 bg-gray-100 rounded-full w-16 h-8 flex items-center justify-center transition-all"
>
<Icon data={faClose} class="text-gray-500" />
</button>
@@ -13,9 +13,8 @@
import Tabs from './common/tabs/Tabs.svelte'
import { FlowGraph, type GraphModuleState } from './graph'
import ModuleStatus from './ModuleStatus.svelte'
import { displayDate, isOwner, truncateRev } from '$lib/utils'
import { displayDate, isOwner, pluralize, truncateRev } from '$lib/utils'
import JobArgs from './JobArgs.svelte'
import autosize from 'svelte-autosize'
import Tooltip from './Tooltip.svelte'
import SimpleEditor from './SimpleEditor.svelte'
@@ -36,6 +35,7 @@
let localFlowModuleStates: Record<string, GraphModuleState> = {}
export let retry_status: Record<string, number> = {}
export let suspend_status: number | undefined = undefined
export let is_owner = false
@@ -69,6 +69,7 @@
}
$: updateFailCount(job?.flow_status?.retry?.fail_count)
$: suspend_status = job?.flow_status?.modules?.[job?.flow_status.step]?.count
function updateFailCount(count?: number) {
if (count) {
@@ -191,9 +192,9 @@
color="green"
variant="border"
on:click={async () =>
await JobService.resumeSuspendedJobAsOwner({
await JobService.resumeSuspendedFlowAsOwner({
workspace: $workspaceStore ?? '',
id: job?.flow_status?.modules?.[job?.flow_status?.step - 1]?.job ?? '',
id: job?.id ?? '',
requestBody: JSON.parse(payload)
})}
>Resume <Tooltip
@@ -264,6 +265,7 @@
</Button>
<div class="border p-6" class:hidden={forloop_selected != loopJobId}>
<svelte:self
bind:suspend_status
bind:retry_status
bind:flowState
bind:flowModuleStates={localFlowModuleStates}
@@ -335,6 +337,7 @@
<li class="w-full border border-gray-600 p-6 space-y-2 bg-blue-50/50">
{#if [FlowStatusModule.type.IN_PROGRESS, FlowStatusModule.type.SUCCESS, FlowStatusModule.type.FAILURE].includes(mod.type)}
<svelte:self
bind:suspend_status
bind:retry_status
bind:flowState
bind:flowModuleStates={localFlowModuleStates}
@@ -395,6 +398,11 @@
Retry in progress, # of failed attempts: {count}
</span>
{/each}
{#if suspend_status}
<span class="text-sm">
Flow suspended, waiting for {pluralize(suspend_status, 'approval')}
</span>
{/if}
</div>
<FlowGraph
@@ -5,7 +5,7 @@
import { getScriptByPath } from '$lib/utils'
export let path: string
export let hash: string | undefined
export let hash: string | undefined = undefined
let code: string
let language: 'deno' | 'python3' | 'go' | 'bash'