feat: no worker with tag warning (#2803)

* feat: no worker with tag warning

* feat: better design and flow jobs

* fix: sqlx

* fix: clear timeout on destroy
This commit is contained in:
HugoCasa
2023-12-08 00:18:41 +01:00
committed by GitHub
parent 825448e1f1
commit 7082c2fbcd
7 changed files with 115 additions and 5 deletions
@@ -0,0 +1,22 @@
{
"db_name": "PostgreSQL",
"query": "SELECT EXISTS(SELECT 1 FROM worker_ping WHERE custom_tags @> $1 AND ping_at > now() - interval '1 minute')",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "exists",
"type_info": "Bool"
}
],
"parameters": {
"Left": [
"TextArray"
]
},
"nullable": [
null
]
},
"hash": "5d1ec728380ea8baf64df54743e73008ee9a58e6f39a5bf31a2ed099727f5c04"
}
+20
View File
@@ -6028,6 +6028,26 @@ paths:
items:
$ref: "#/components/schemas/WorkerPing"
/workers/exists_worker_with_tag:
get:
summary: exists worker with tag
operationId: existsWorkerWithTag
tags:
- worker
parameters:
- name: tag
in: query
required: true
schema:
type: string
responses:
"200":
description: whether a worker with the tag exists
content:
application/json:
schema:
type: boolean
/configs/list_worker_groups:
get:
summary: list worker groups
+22
View File
@@ -26,6 +26,7 @@ use crate::db::ApiAuthed;
pub fn global_service() -> Router {
Router::new()
.route("/list", get(list_worker_pings))
.route("/exists_worker_with_tag", get(exists_worker_with_tag))
.route("/custom_tags", get(get_custom_tags))
}
@@ -68,6 +69,27 @@ async fn list_worker_pings(
Ok(Json(rows))
}
#[derive(Serialize, Deserialize)]
struct TagQuery {
tag: String,
}
async fn exists_worker_with_tag(
authed: ApiAuthed,
Extension(user_db): Extension<UserDB>,
Query(tag_query): Query<TagQuery>,
) -> JsonResult<bool> {
let mut tx = user_db.begin(&authed).await?;
let row = sqlx::query!(
"SELECT EXISTS(SELECT 1 FROM worker_ping WHERE custom_tags @> $1 AND ping_at > now() - interval '1 minute')",
&[tag_query.tag]
)
.fetch_one(&mut *tx)
.await?;
tx.commit().await?;
Ok(Json(row.exists.unwrap_or(false)))
}
async fn get_custom_tags() -> Json<Vec<String>> {
Json(ALL_TAGS.read().await.clone().into())
}
+3 -1
View File
@@ -5,6 +5,7 @@
import { forLater } from '$lib/forLater'
import DurationMs from './DurationMs.svelte'
import { Calendar, CheckCircle2, Circle, Clock, XCircle } from 'lucide-svelte'
import NoWorkerWithTagWarning from './runs/NoWorkerWithTagWarning.svelte'
const SMALL_ICON_SIZE = 12
@@ -39,8 +40,9 @@
</Badge>
</div>
{:else if job && 'running' in job}
<div>
<div class="flex flex-row gap-1 items-center">
<Badge icon={{ icon: Clock, position: 'left' }}>Queued</Badge>
<NoWorkerWithTagWarning tag={job.tag} />
</div>
{:else}
<Circle size={SMALL_ICON_SIZE} class="text-gray-200" />
+6 -2
View File
@@ -4,6 +4,7 @@
import { copyToClipboard } from '$lib/utils'
import { workspaceStore } from '$lib/stores'
import AnsiUp from 'ansi_up'
import NoWorkerWithTagWarning from './runs/NoWorkerWithTagWarning.svelte'
export let content: string | undefined
export let isLoading: boolean
@@ -89,10 +90,13 @@
</div>
</div>
{#if isLoading}
<div class="flex gap-2 absolute top-2 left-2 items-center">
<div class="flex gap-2 absolute top-2 left-2 items-center z-10">
<Loader2 class="animate-spin" />
{#if tag}
<div class="text-secondary {small ? '!text-2xs' : '!text-xs'}">tag: {tag}</div>
<div class="flex flex-row items-center gap-1">
<div class="text-secondary {small ? '!text-2xs' : '!text-xs'}">tag: {tag}</div>
<NoWorkerWithTagWarning {tag} />
</div>
{/if}
</div>
{:else if duration}
+2 -2
View File
@@ -4,7 +4,7 @@
import Portal from 'svelte-portal'
import { ExternalLink } from 'lucide-svelte'
export let placement: PopoverPlacement = 'auto'
export let placement: PopoverPlacement = 'bottom-end'
export let notClickable = false
export let popupClass = ''
export let disablePopup = false
@@ -16,7 +16,7 @@
const [popperRef, popperContent] = createPopperActions({ placement })
const popperOptions: PopperOptions<{}> = {
placement: 'bottom-end',
placement,
strategy: 'fixed',
modifiers: [
{ name: 'offset', options: { offset: [8, 8] } },
@@ -0,0 +1,40 @@
<script lang="ts">
import { WorkerService } from '$lib/gen'
import { AlertTriangle } from 'lucide-svelte'
import Popover from '../Popover.svelte'
import { onDestroy } from 'svelte'
export let tag: string
let noWorkerWithTag = false
let timeout: NodeJS.Timeout | undefined = undefined
async function lookForTag(): Promise<void> {
try {
const existsWorkerWithTag = await WorkerService.existsWorkerWithTag({ tag })
noWorkerWithTag = !existsWorkerWithTag
timeout = setTimeout(() => {
lookForTag()
}, 1000)
} catch (err) {
console.error(err)
}
}
lookForTag()
onDestroy(() => {
if (timeout) {
clearTimeout(timeout)
}
})
</script>
{#if noWorkerWithTag}
<Popover notClickable placement="top">
<AlertTriangle size={16} class="text-yellow-500" />
<svelte:fragment slot="text">
No worker with tag <b>{tag}</b> is currently running.
</svelte:fragment>
</Popover>
{/if}