Files
windmill/frontend/src/lib/components/FlowMetadata.svelte
T
wendrul 60b036c1ae Add concurrency limits observability (#3586)
* Add concurrency_key table and field to payload

Add a new table custom_concurrency_key for storing concurrency keys on a
per job basis. Add the field to the job payload to populate the table on
creation of a new job.

* Rename to custom_concurrency_key

Be more explicit about the nature of the option variable by calling it
a more appropriate name.

* Delete concurrency_keys on delete_expire_items

* Propagate db errors up

* Add ref to EE changes

* update sqlx

* Add concurrency_key to tests

* Revert renaming of FlowValue field

FlowValue field concurrency_key must be named concurrency_key for
serialization purposes.

* Remove debug print statement

* Get concurrency_key from Job

Whether it is a Completed job or a queued one, add a ways to get the
associated concurrency key

* Add endpoint to get concurrency_key

* Add endpoint and button to get job concurrency_key

Add a line with a link on the FlowMetadata that goes to the
concurrency_groups page. add endpoint to get the concurrency_key of a
job

* Merge concurrency_key tables into one

migration + change all related querrys

* Add concurrency plot to the runs page

* Prepare sqlx

* Add concurrency Key filter on UI

* Prepare sqlx

* Prepare sqlx

* Fix filter and order query

The limit makes more sense if we cut the older rows, so order by
started_at

* Factor interpolation to reuse on concurrency key

Factor the arg interpolation logic into a function and finish the
processing of concurrency key before insertion

* Remove old concurrency key processing logic

* Second transaction with userdb

To send all concurrency intervals but revealing only uuids of accessible
jobs, make a second transaction with the userdb.

* Remove old second endpoint

the intervals endpoint now also gets the concurrencyt key information
for all jobs

* Show external jobs

* Put filters into a dropdown

Create a ToggleButtonMore and put elements into a dropdown

* Add toggle between two graphs

* Add filter functionality to concurrency graph

* Improve concurrency graph front

* Fix concurrency groups page

* Prepare sqlx

* Add ref to ee

* Change migration to create new table instead

Instead of renaming the custom_concurrency_key_ended atble, we create a
new table and we will delete custom_concurrency_key_ended in the future
when it is no longer linked to any jobs

* Do small UI improvements

* Fix range fusion by not filtering past jobs

Instead of filtering jobs in the backend on a startedAfter value, limit
the query to 1000 and query all possible towards the past to get a good
context for the graph in most sane situations

* Improve frontend UI
2024-05-15 20:15:14 +02:00

117 lines
3.7 KiB
Svelte

<script lang="ts">
import { type Job } from '$lib/gen'
import JobStatus from '$lib/components/JobStatus.svelte'
import { displayDate } from '$lib/utils'
import ScheduleEditor from './ScheduleEditor.svelte'
import TimeAgo from './TimeAgo.svelte'
import { workspaceStore } from '$lib/stores'
import Tooltip from './Tooltip.svelte'
import { Clock, MemoryStick, Calendar, Bot, User, Code2 } from 'lucide-svelte'
import BarsStaggered from '$lib/components/icons/BarsStaggered.svelte'
export let job: Job
const SMALL_ICON_SIZE = 14
export let scheduleEditor: ScheduleEditor
</script>
<div
class="rounded-md p-3 bg-surface-secondary shadow-sm sm:text-sm md:text-base"
style="min-height: 150px;"
>
<JobStatus {job} />
<div class="flex flex-row gap-2 items-center">
<Clock size={SMALL_ICON_SIZE} class="text-secondary" />
<span class="text-2xs text-secondary">
{#if job['success'] != undefined}
Received job: {displayDate(job.created_at ?? '')}
{:else}
Received job <TimeAgo date={job.created_at ?? ''} />
{/if}
<Tooltip>{job?.created_at}</Tooltip>
</span>
</div>
{#if job && 'started_at' in job && job.started_at}
<div class="flex flex-row gap-2 items-center">
<Clock size={SMALL_ICON_SIZE} class="text-secondary" />
<span>
Started <TimeAgo withDate agoOnlyIfRecent date={job.started_at ?? ''} />
<Tooltip>{job?.started_at}</Tooltip>
</span>
</div>
{/if}
{#if job && job['mem_peak']}
<div class="flex flex-row gap-2 items-center">
<MemoryStick size={SMALL_ICON_SIZE} class="text-secondary" />
<span> Mem peak: {(job['mem_peak'] / 1024).toPrecision(5)}MB</span>
</div>
{/if}
<div>
{#if job && job.parent_job}
{#if job.is_flow_step}
<div class="flex flex-row gap-2 items-center">
<BarsStaggered size={SMALL_ICON_SIZE} class="text-secondary" />
<span>
Step of flow
<a href={`/run/${job.parent_job}?workspace=${$workspaceStore}`}>
{job.parent_job}
</a>
</span>
</div>
{:else}
<div class="flex flex-row gap-2 items-center">
<Bot size={SMALL_ICON_SIZE} class="text-secondary" />
<span>
Triggered by parent
<a href={`/run/${job.parent_job}?workspace=${$workspaceStore}`}> {job.parent_job}</a>
</span>
</div>
{/if}
{:else if job && job.schedule_path}
<div class="flex flex-row gap-2 items-center">
<Calendar size={SMALL_ICON_SIZE} class="text-secondary" />
<span>
Triggered by the schedule:
<button
class="break-words text-sm text-blue-600 font-normal"
on:click={() =>
scheduleEditor?.openEdit(job.schedule_path ?? '', job.job_kind == 'flow')}
>
{job.schedule_path}
</button>
</span>
</div>
{/if}
{#if (job && job.job_kind == 'flow') || job?.job_kind == 'script'}
{@const stem = `/${job?.job_kind}s`}
{@const isScript = job?.job_kind === 'script'}
{@const viewHref = `${stem}/get/${isScript ? job?.script_hash : job?.script_path}`}
<div class="flex flex-row gap-2 items-center ml-0.5">
{#if isScript}
<Code2 size={SMALL_ICON_SIZE} class="text-secondary" />
{:else}
<BarsStaggered size={SMALL_ICON_SIZE} class="text-secondary" />
{/if}
<span class="truncate text-sm">
<a href={viewHref}>{isScript ? job?.script_hash : job?.script_path}</a>
</span>
</div>
{/if}
<div class="flex flex-row gap-2 items-center text-sm">
<User size={SMALL_ICON_SIZE} class="text-secondary" />
<span>
By {job.created_by}
{#if job.permissioned_as !== `u/${job.created_by}` && job.permissioned_as != job.created_by}
but permissioned as {job.permissioned_as}
{/if}
</span>
</div>
</div>
<div class="text-secondary text-2xs pt-2">
run id:
<a href={`/run/${job.id}?workspace=${job.workspace_id}`}> {job.id} </a>
</div>
</div>