@pg-boss/dashboard 1.3.0 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -1 +1 @@
|
|
|
1
|
-
window.__reactRouterManifest={"entry":{"module":"/assets/entry.client-CqyjuPDB.js","imports":["/assets/jsx-runtime-RQyiN6Nr.js","/assets/react-dom-D_m_Zgd3.js"],"css":[]},"routes":{"root":{"id":"root","path":"","hasAction":false,"hasLoader":true,"hasClientAction":false,"hasClientLoader":false,"hasClientMiddleware":false,"hasDefaultExport":true,"hasErrorBoundary":true,"module":"/assets/root-qxoeL6W3.js","imports":["/assets/jsx-runtime-RQyiN6Nr.js","/assets/react-dom-D_m_Zgd3.js","/assets/db-link-BajQ1v8I.js","/assets/createLucideIcon-C-LI4enx.js","/assets/MenuTrigger-BNvpjhsQ.js","/assets/useOpenInteractionType-BQ1arb0B.js"],"css":["/assets/root-B0MB8jZH.css"]},"routes/_index":{"id":"routes/_index","parentId":"root","index":true,"hasAction":false,"hasLoader":true,"hasClientAction":false,"hasClientLoader":false,"hasClientMiddleware":false,"hasDefaultExport":true,"hasErrorBoundary":true,"module":"/assets/_index-DqpFaaQw.js","imports":["/assets/jsx-runtime-RQyiN6Nr.js","/assets/db-link-BajQ1v8I.js","/assets/stat-card-dyg1wY5p.js","/assets/button-9NpSS9Ow.js","/assets/badge-CMnQO7Lq.js","/assets/table-Cz7ujmH_.js","/assets/error-card-BH7i86fH.js"],"css":[]},"routes/jobs":{"id":"routes/jobs","parentId":"root","path":"jobs","hasAction":false,"hasLoader":true,"hasClientAction":false,"hasClientLoader":false,"hasClientMiddleware":false,"hasDefaultExport":true,"hasErrorBoundary":true,"module":"/assets/jobs-CAd_qqLH.js","imports":["/assets/jsx-runtime-RQyiN6Nr.js","/assets/db-link-BajQ1v8I.js","/assets/createLucideIcon-C-LI4enx.js","/assets/check-7jwc5sb1.js","/assets/chevron-down-BFFjfYD4.js","/assets/chevron-right-DGk5QFJF.js","/assets/x-AhXI_F1j.js","/assets/MenuTrigger-BNvpjhsQ.js","/assets/useOpenInteractionType-BQ1arb0B.js","/assets/button-9NpSS9Ow.js","/assets/badge-CMnQO7Lq.js","/assets/table-Cz7ujmH_.js","/assets/error-card-BH7i86fH.js","/assets/pagination-C-ohiBmY.js","/assets/filter-select-Bn_oSiip.js","/assets/react-dom-D_m_Zgd3.js"],"css":[]},"routes/queues._index":{"id":"routes/queues._index","parentId":"root","path":"queues","hasAction":false,"hasLoader":true,"hasClientAction":false,"hasClientLoader":false,"hasClientMiddleware":false,"hasDefaultExport":true,"hasErrorBoundary":true,"module":"/assets/queues._index-8YriSqbQ.js","imports":["/assets/jsx-runtime-RQyiN6Nr.js","/assets/db-link-BajQ1v8I.js","/assets/button-9NpSS9Ow.js","/assets/badge-CMnQO7Lq.js","/assets/table-Cz7ujmH_.js","/assets/filter-select-Bn_oSiip.js"],"css":[]},"routes/queues.create":{"id":"routes/queues.create","parentId":"root","path":"queues/create","hasAction":true,"hasLoader":true,"hasClientAction":false,"hasClientLoader":false,"hasClientMiddleware":false,"hasDefaultExport":true,"hasErrorBoundary":true,"module":"/assets/queues.create-DsY0Sc19.js","imports":["/assets/jsx-runtime-RQyiN6Nr.js","/assets/db-link-BajQ1v8I.js","/assets/chevron-down-BFFjfYD4.js","/assets/button-9NpSS9Ow.js","/assets/error-card-BH7i86fH.js","/assets/createLucideIcon-C-LI4enx.js"],"css":[]},"routes/queues.$name":{"id":"routes/queues.$name","parentId":"root","path":"queues/:name","hasAction":true,"hasLoader":true,"hasClientAction":false,"hasClientLoader":false,"hasClientMiddleware":false,"hasDefaultExport":true,"hasErrorBoundary":true,"module":"/assets/queues._name-Cb17IB2u.js","imports":["/assets/jsx-runtime-RQyiN6Nr.js","/assets/db-link-BajQ1v8I.js","/assets/createLucideIcon-C-LI4enx.js","/assets/chevron-down-BFFjfYD4.js","/assets/chevron-right-DGk5QFJF.js","/assets/MenuTrigger-BNvpjhsQ.js","/assets/dialog-D-oczDM2.js","/assets/stat-card-dyg1wY5p.js","/assets/button-9NpSS9Ow.js","/assets/badge-CMnQO7Lq.js","/assets/table-Cz7ujmH_.js","/assets/error-card-BH7i86fH.js","/assets/pagination-C-ohiBmY.js","/assets/filter-select-Bn_oSiip.js","/assets/react-dom-D_m_Zgd3.js","/assets/useOpenInteractionType-BQ1arb0B.js","/assets/x-AhXI_F1j.js"],"css":[]},"routes/queues.$name.jobs.$jobId":{"id":"routes/queues.$name.jobs.$jobId","parentId":"root","path":"queues/:name/jobs/:jobId","hasAction":true,"hasLoader":true,"hasClientAction":false,"hasClientLoader":false,"hasClientMiddleware":false,"hasDefaultExport":true,"hasErrorBoundary":true,"module":"/assets/queues._name.jobs._jobId-
|
|
1
|
+
window.__reactRouterManifest={"entry":{"module":"/assets/entry.client-CqyjuPDB.js","imports":["/assets/jsx-runtime-RQyiN6Nr.js","/assets/react-dom-D_m_Zgd3.js"],"css":[]},"routes":{"root":{"id":"root","path":"","hasAction":false,"hasLoader":true,"hasClientAction":false,"hasClientLoader":false,"hasClientMiddleware":false,"hasDefaultExport":true,"hasErrorBoundary":true,"module":"/assets/root-qxoeL6W3.js","imports":["/assets/jsx-runtime-RQyiN6Nr.js","/assets/react-dom-D_m_Zgd3.js","/assets/db-link-BajQ1v8I.js","/assets/createLucideIcon-C-LI4enx.js","/assets/MenuTrigger-BNvpjhsQ.js","/assets/useOpenInteractionType-BQ1arb0B.js"],"css":["/assets/root-B0MB8jZH.css"]},"routes/_index":{"id":"routes/_index","parentId":"root","index":true,"hasAction":false,"hasLoader":true,"hasClientAction":false,"hasClientLoader":false,"hasClientMiddleware":false,"hasDefaultExport":true,"hasErrorBoundary":true,"module":"/assets/_index-DqpFaaQw.js","imports":["/assets/jsx-runtime-RQyiN6Nr.js","/assets/db-link-BajQ1v8I.js","/assets/stat-card-dyg1wY5p.js","/assets/button-9NpSS9Ow.js","/assets/badge-CMnQO7Lq.js","/assets/table-Cz7ujmH_.js","/assets/error-card-BH7i86fH.js"],"css":[]},"routes/jobs":{"id":"routes/jobs","parentId":"root","path":"jobs","hasAction":false,"hasLoader":true,"hasClientAction":false,"hasClientLoader":false,"hasClientMiddleware":false,"hasDefaultExport":true,"hasErrorBoundary":true,"module":"/assets/jobs-CAd_qqLH.js","imports":["/assets/jsx-runtime-RQyiN6Nr.js","/assets/db-link-BajQ1v8I.js","/assets/createLucideIcon-C-LI4enx.js","/assets/check-7jwc5sb1.js","/assets/chevron-down-BFFjfYD4.js","/assets/chevron-right-DGk5QFJF.js","/assets/x-AhXI_F1j.js","/assets/MenuTrigger-BNvpjhsQ.js","/assets/useOpenInteractionType-BQ1arb0B.js","/assets/button-9NpSS9Ow.js","/assets/badge-CMnQO7Lq.js","/assets/table-Cz7ujmH_.js","/assets/error-card-BH7i86fH.js","/assets/pagination-C-ohiBmY.js","/assets/filter-select-Bn_oSiip.js","/assets/react-dom-D_m_Zgd3.js"],"css":[]},"routes/queues._index":{"id":"routes/queues._index","parentId":"root","path":"queues","hasAction":false,"hasLoader":true,"hasClientAction":false,"hasClientLoader":false,"hasClientMiddleware":false,"hasDefaultExport":true,"hasErrorBoundary":true,"module":"/assets/queues._index-8YriSqbQ.js","imports":["/assets/jsx-runtime-RQyiN6Nr.js","/assets/db-link-BajQ1v8I.js","/assets/button-9NpSS9Ow.js","/assets/badge-CMnQO7Lq.js","/assets/table-Cz7ujmH_.js","/assets/filter-select-Bn_oSiip.js"],"css":[]},"routes/queues.create":{"id":"routes/queues.create","parentId":"root","path":"queues/create","hasAction":true,"hasLoader":true,"hasClientAction":false,"hasClientLoader":false,"hasClientMiddleware":false,"hasDefaultExport":true,"hasErrorBoundary":true,"module":"/assets/queues.create-DsY0Sc19.js","imports":["/assets/jsx-runtime-RQyiN6Nr.js","/assets/db-link-BajQ1v8I.js","/assets/chevron-down-BFFjfYD4.js","/assets/button-9NpSS9Ow.js","/assets/error-card-BH7i86fH.js","/assets/createLucideIcon-C-LI4enx.js"],"css":[]},"routes/queues.$name":{"id":"routes/queues.$name","parentId":"root","path":"queues/:name","hasAction":true,"hasLoader":true,"hasClientAction":false,"hasClientLoader":false,"hasClientMiddleware":false,"hasDefaultExport":true,"hasErrorBoundary":true,"module":"/assets/queues._name-Cb17IB2u.js","imports":["/assets/jsx-runtime-RQyiN6Nr.js","/assets/db-link-BajQ1v8I.js","/assets/createLucideIcon-C-LI4enx.js","/assets/chevron-down-BFFjfYD4.js","/assets/chevron-right-DGk5QFJF.js","/assets/MenuTrigger-BNvpjhsQ.js","/assets/dialog-D-oczDM2.js","/assets/stat-card-dyg1wY5p.js","/assets/button-9NpSS9Ow.js","/assets/badge-CMnQO7Lq.js","/assets/table-Cz7ujmH_.js","/assets/error-card-BH7i86fH.js","/assets/pagination-C-ohiBmY.js","/assets/filter-select-Bn_oSiip.js","/assets/react-dom-D_m_Zgd3.js","/assets/useOpenInteractionType-BQ1arb0B.js","/assets/x-AhXI_F1j.js"],"css":[]},"routes/queues.$name.jobs.$jobId":{"id":"routes/queues.$name.jobs.$jobId","parentId":"root","path":"queues/:name/jobs/:jobId","hasAction":true,"hasLoader":true,"hasClientAction":false,"hasClientLoader":false,"hasClientMiddleware":false,"hasDefaultExport":true,"hasErrorBoundary":true,"module":"/assets/queues._name.jobs._jobId-DzHZmfcB.js","imports":["/assets/jsx-runtime-RQyiN6Nr.js","/assets/db-link-BajQ1v8I.js","/assets/createLucideIcon-C-LI4enx.js","/assets/check-7jwc5sb1.js","/assets/dialog-D-oczDM2.js","/assets/button-9NpSS9Ow.js","/assets/badge-CMnQO7Lq.js","/assets/error-card-BH7i86fH.js","/assets/x-AhXI_F1j.js","/assets/useOpenInteractionType-BQ1arb0B.js","/assets/react-dom-D_m_Zgd3.js"],"css":[]},"routes/schedules":{"id":"routes/schedules","parentId":"root","path":"schedules","hasAction":false,"hasLoader":true,"hasClientAction":false,"hasClientLoader":false,"hasClientMiddleware":false,"hasDefaultExport":true,"hasErrorBoundary":true,"module":"/assets/schedules-iYfIJxOD.js","imports":["/assets/jsx-runtime-RQyiN6Nr.js","/assets/db-link-BajQ1v8I.js","/assets/button-9NpSS9Ow.js","/assets/badge-CMnQO7Lq.js","/assets/table-Cz7ujmH_.js","/assets/error-card-BH7i86fH.js","/assets/pagination-C-ohiBmY.js"],"css":[]},"routes/schedules.$name.$key":{"id":"routes/schedules.$name.$key","parentId":"root","path":"schedules/:name/:key","hasAction":true,"hasLoader":true,"hasClientAction":false,"hasClientLoader":false,"hasClientMiddleware":false,"hasDefaultExport":true,"hasErrorBoundary":true,"module":"/assets/schedules._name._key-CJVu73XY.js","imports":["/assets/jsx-runtime-RQyiN6Nr.js","/assets/db-link-BajQ1v8I.js","/assets/dialog-D-oczDM2.js","/assets/button-9NpSS9Ow.js","/assets/error-card-BH7i86fH.js","/assets/x-AhXI_F1j.js","/assets/useOpenInteractionType-BQ1arb0B.js","/assets/createLucideIcon-C-LI4enx.js","/assets/react-dom-D_m_Zgd3.js"],"css":[]},"routes/schedules.new":{"id":"routes/schedules.new","parentId":"root","path":"schedules/new","hasAction":true,"hasLoader":true,"hasClientAction":false,"hasClientLoader":false,"hasClientMiddleware":false,"hasDefaultExport":true,"hasErrorBoundary":true,"module":"/assets/schedules.new-Cq0Mxa7G.js","imports":["/assets/jsx-runtime-RQyiN6Nr.js","/assets/db-link-BajQ1v8I.js","/assets/button-9NpSS9Ow.js","/assets/error-card-BH7i86fH.js"],"css":[]},"routes/send":{"id":"routes/send","parentId":"root","path":"send","hasAction":true,"hasLoader":true,"hasClientAction":false,"hasClientLoader":false,"hasClientMiddleware":false,"hasDefaultExport":true,"hasErrorBoundary":true,"module":"/assets/send-8X9ZisG-.js","imports":["/assets/jsx-runtime-RQyiN6Nr.js","/assets/db-link-BajQ1v8I.js","/assets/button-9NpSS9Ow.js","/assets/error-card-BH7i86fH.js"],"css":[]},"routes/migrations":{"id":"routes/migrations","parentId":"root","path":"migrations","hasAction":false,"hasLoader":true,"hasClientAction":false,"hasClientLoader":false,"hasClientMiddleware":false,"hasDefaultExport":true,"hasErrorBoundary":true,"module":"/assets/migrations-D5l0n4Jn.js","imports":["/assets/jsx-runtime-RQyiN6Nr.js","/assets/db-link-BajQ1v8I.js","/assets/stat-card-dyg1wY5p.js","/assets/button-9NpSS9Ow.js","/assets/badge-CMnQO7Lq.js","/assets/table-Cz7ujmH_.js","/assets/error-card-BH7i86fH.js","/assets/pagination-C-ohiBmY.js","/assets/filter-select-Bn_oSiip.js"],"css":[]},"routes/warnings":{"id":"routes/warnings","parentId":"root","path":"warnings","hasAction":false,"hasLoader":true,"hasClientAction":false,"hasClientLoader":false,"hasClientMiddleware":false,"hasDefaultExport":true,"hasErrorBoundary":true,"module":"/assets/warnings-C1R_RzIe.js","imports":["/assets/jsx-runtime-RQyiN6Nr.js","/assets/db-link-BajQ1v8I.js","/assets/button-9NpSS9Ow.js","/assets/badge-CMnQO7Lq.js","/assets/table-Cz7ujmH_.js","/assets/error-card-BH7i86fH.js","/assets/pagination-C-ohiBmY.js","/assets/filter-select-Bn_oSiip.js"],"css":[]}},"url":"/assets/manifest-3e8f868c.js","version":"3e8f868c"};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{o as e,rt as t,s as n,t as r,tt as i}from"./jsx-runtime-RQyiN6Nr.js";import{h as a,j as o,m as s,t as c,u as l}from"./db-link-BajQ1v8I.js";import{t as u}from"./createLucideIcon-C-LI4enx.js";import{t as d}from"./check-7jwc5sb1.js";import{a as f,i as p,n as m,o as h,r as g,t as _}from"./dialog-D-oczDM2.js";import{a as v,i as y,n as b,r as x,t as S}from"./button-9NpSS9Ow.js";import{n as C,t as w}from"./badge-CMnQO7Lq.js";import{t as T}from"./error-card-BH7i86fH.js";var E=u(`copy`,[[`rect`,{width:`14`,height:`14`,x:`8`,y:`8`,rx:`2`,ry:`2`,key:`17jyea`}],[`path`,{d:`M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2`,key:`zix9uf`}]]),D=t(i(),1),O=r();function k({title:e,description:t,confirmLabel:n,confirmVariant:r=`primary`,triggerVariant:i=`ghost`,trigger:a,onConfirm:o,disabled:s}){let[c,l]=(0,D.useState)(!1);return(0,O.jsxs)(f,{open:c,onOpenChange:l,children:[(0,O.jsx)(S,{variant:i,size:`sm`,disabled:s,onClick:()=>l(!0),className:`cursor-pointer`,children:a}),(0,O.jsxs)(_,{hideCloseButton:!0,className:`w-[28rem] max-w-[calc(100vw-2rem)]`,children:[(0,O.jsxs)(p,{children:[(0,O.jsx)(h,{children:e}),(0,O.jsx)(m,{className:`mt-2`,children:t})]}),(0,O.jsxs)(g,{className:`mt-6 flex justify-end gap-3`,children:[(0,O.jsx)(S,{variant:`outline`,size:`sm`,className:`cursor-pointer`,onClick:()=>l(!1),children:`Cancel`}),(0,O.jsx)(S,{variant:r===`danger`?`danger`:`primary`,size:`sm`,className:`cursor-pointer`,onClick:()=>{o(),l(!1)},children:n})]})]})]})}var A=n(function(){return(0,O.jsx)(T,{title:`Failed to load job`,backTo:{href:`/queues`,label:`Back to Queues`}})}),j=e(function({loaderData:e}){let{job:t,queueName:n}=e,r=o(),i=r.state!==`idle`,[u,f]=(0,D.useState)(!1),p=r.data,m=p&&!p.success&&p.affected===0,h=e=>{r.submit({intent:e},{method:`post`})},g=async()=>{await navigator.clipboard.writeText(t.id),f(!0),setTimeout(()=>f(!1),2e3)},_=t.state===`failed`;return(0,O.jsxs)(`div`,{className:`space-y-4`,children:[(0,O.jsx)(C,{title:(0,O.jsxs)(`span`,{className:`inline-flex items-center gap-3`,children:[`Job detail`,(0,O.jsx)(w,{variant:l[t.state],size:`lg`,dot:!0,children:t.state})]}),action:(0,O.jsxs)(`div`,{className:`flex items-center gap-2`,children:[m&&(0,O.jsx)(`span`,{className:`text-xs text-[var(--warning-600)]`,title:p.message,children:`Action failed`}),t.state===`failed`&&(0,O.jsx)(S,{variant:`outline`,size:`sm`,disabled:i,onClick:()=>h(`retry`),children:`Retry`}),t.state===`cancelled`&&(0,O.jsx)(S,{variant:`outline`,size:`sm`,disabled:i,onClick:()=>h(`resume`),children:`Resume`}),(t.state===`created`||t.state===`retry`||t.state===`active`)&&(0,O.jsx)(k,{title:`Cancel Job`,description:`Are you sure you want to cancel job ${t.id.slice(0,8)}...? This will prevent the job from being processed.`,confirmLabel:`Cancel Job`,confirmVariant:`danger`,triggerVariant:`outline`,trigger:`Cancel`,onConfirm:()=>h(`cancel`),disabled:i}),t.state!==`active`&&(0,O.jsx)(k,{title:`Delete Job`,description:`Are you sure you want to delete job ${t.id.slice(0,8)}...? This action cannot be undone.`,confirmLabel:`Delete`,confirmVariant:`danger`,triggerVariant:`danger`,trigger:`Delete`,onConfirm:()=>h(`delete`),disabled:i})]})}),(0,O.jsxs)(b,{children:[(0,O.jsxs)(y,{children:[(0,O.jsx)(v,{children:`Details`}),(0,O.jsxs)(`span`,{className:`text-xs text-[var(--text-tertiary)]`,children:[`in queue`,` `,(0,O.jsx)(c,{to:`/queues/${encodeURIComponent(n)}`,className:`font-mono text-xs text-primary-600 hover:text-primary-700 dark:text-primary-400 dark:hover:text-primary-300`,children:n})]})]}),(0,O.jsxs)(x,{className:`space-y-6`,children:[(0,O.jsxs)(`div`,{className:`grid grid-cols-1 sm:grid-cols-[2fr_1fr_1fr] gap-6`,children:[(0,O.jsxs)(`div`,{children:[(0,O.jsx)(`div`,{className:`pgb-eyebrow mb-1`,children:`Job ID`}),(0,O.jsxs)(`div`,{className:`flex items-center gap-1.5`,children:[(0,O.jsx)(`code`,{className:`text-sm font-mono break-all text-[var(--text-primary)]`,children:t.id}),(0,O.jsx)(`button`,{onClick:g,className:s(`p-1 rounded-md transition-colors cursor-pointer flex-shrink-0`,`text-[var(--text-tertiary)] hover:text-[var(--text-primary)] hover:bg-[var(--surface-hover)]`),title:u?`Copied!`:`Copy to clipboard`,children:u?(0,O.jsx)(d,{className:`h-4 w-4 text-[var(--success-600)]`}):(0,O.jsx)(E,{className:`h-4 w-4`})})]})]}),(0,O.jsx)(M,{label:`Policy`,value:t.policy||`—`}),(0,O.jsx)(M,{label:`Priority`,value:t.priority,mono:!0})]}),(0,O.jsxs)(`div`,{className:`grid grid-cols-1 lg:grid-cols-2 gap-4`,children:[(0,O.jsxs)(`div`,{children:[(0,O.jsx)(`div`,{className:`pgb-eyebrow mb-1.5`,children:`Data`}),(0,O.jsx)(`pre`,{className:`text-xs px-3.5 py-3 rounded-lg border border-[var(--border-default)] bg-[var(--surface-sunken)] font-mono leading-relaxed text-[var(--text-primary)] overflow-auto max-h-40`,children:t.data?JSON.stringify(t.data,null,2):`null`})]}),(0,O.jsxs)(`div`,{children:[(0,O.jsx)(`div`,{className:`pgb-eyebrow mb-1.5`,children:`Output`}),(0,O.jsx)(`pre`,{className:s(`text-xs px-3.5 py-3 rounded-lg border font-mono leading-relaxed text-[var(--text-primary)] overflow-auto max-h-40`,_?`border-[var(--error-100)] bg-[var(--error-50)]`:`border-[var(--border-default)] bg-[var(--surface-sunken)]`),children:t.output!==void 0&&t.output!==null?JSON.stringify(t.output,null,2):`—`})]})]}),(0,O.jsx)(`div`,{children:(0,O.jsxs)(`div`,{className:`space-y-6`,children:[(0,O.jsx)(`div`,{className:`grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-x-6 gap-y-4`,children:(0,O.jsx)(M,{label:`Priority`,value:t.priority})}),(0,O.jsxs)(`div`,{className:`grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-x-6 gap-y-4`,children:[(0,O.jsx)(M,{label:`Retry Count`,value:t.retryCount,mono:!0}),(0,O.jsx)(M,{label:`Retry Limit`,value:t.retryLimit,mono:!0}),(0,O.jsx)(M,{label:`Retry Delay`,value:t.retryDelay?`${t.retryDelay}ms`:`—`,mono:!0}),(0,O.jsx)(M,{label:`Retry Backoff`,value:t.retryBackoff?`Enabled`:`Disabled`})]}),(t.singletonKey||t.groupId||t.groupTier||t.deadLetter)&&(0,O.jsxs)(`div`,{className:`grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-x-6 gap-y-4`,children:[t.singletonKey&&(0,O.jsx)(M,{label:`Singleton Key`,value:t.singletonKey,mono:!0}),t.groupId&&(0,O.jsx)(M,{label:`Group ID`,value:t.groupId,mono:!0}),t.groupTier&&(0,O.jsx)(M,{label:`Group Tier`,value:t.groupTier,mono:!0}),t.deadLetter&&(0,O.jsxs)(`div`,{children:[(0,O.jsx)(`dt`,{className:`pgb-eyebrow`,children:`Dead Letter`}),(0,O.jsx)(`dd`,{className:`mt-1 text-sm text-[var(--text-primary)]`,children:(0,O.jsx)(c,{to:`/queues/${t.deadLetter}`,className:`font-mono text-xs text-primary-600 hover:text-primary-700 dark:text-primary-400 dark:hover:text-primary-300`,children:t.deadLetter})})]})]}),(0,O.jsxs)(`div`,{className:`grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-5 gap-x-6 gap-y-4`,children:[(0,O.jsx)(M,{label:`Created`,value:a(new Date(t.createdOn)),mono:!0}),(0,O.jsx)(M,{label:`Start After`,value:t.startAfter?a(new Date(t.startAfter)):`—`,mono:!0}),(0,O.jsx)(M,{label:`Started`,value:t.startedOn?a(new Date(t.startedOn)):`—`,mono:!0}),(0,O.jsx)(M,{label:`Completed`,value:t.completedOn?a(new Date(t.completedOn)):`—`,mono:!0}),(0,O.jsx)(M,{label:`Keep Until`,value:t.keepUntil?a(new Date(t.keepUntil)):`—`,mono:!0})]})]})})]})]})]})});function M({label:e,value:t,mono:n=!1}){return(0,O.jsxs)(`div`,{children:[(0,O.jsx)(`dt`,{className:`pgb-eyebrow`,children:e}),(0,O.jsx)(`dd`,{className:s(`mt-1 text-sm text-[var(--text-primary)]`,n&&`pgb-num`),children:t?.toString()||`—`})]})}export{A as ErrorBoundary,j as default};
|
|
1
|
+
import{o as e,rt as t,s as n,t as r,tt as i}from"./jsx-runtime-RQyiN6Nr.js";import{h as a,j as o,m as s,t as c,u as l}from"./db-link-BajQ1v8I.js";import{t as u}from"./createLucideIcon-C-LI4enx.js";import{t as d}from"./check-7jwc5sb1.js";import{a as f,i as p,n as m,o as h,r as g,t as _}from"./dialog-D-oczDM2.js";import{a as v,i as y,n as b,r as x,t as S}from"./button-9NpSS9Ow.js";import{n as C,t as w}from"./badge-CMnQO7Lq.js";import{t as T}from"./error-card-BH7i86fH.js";var E=u(`copy`,[[`rect`,{width:`14`,height:`14`,x:`8`,y:`8`,rx:`2`,ry:`2`,key:`17jyea`}],[`path`,{d:`M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2`,key:`zix9uf`}]]),D=t(i(),1),O=r();function k({title:e,description:t,confirmLabel:n,confirmVariant:r=`primary`,triggerVariant:i=`ghost`,trigger:a,onConfirm:o,disabled:s}){let[c,l]=(0,D.useState)(!1);return(0,O.jsxs)(f,{open:c,onOpenChange:l,children:[(0,O.jsx)(S,{variant:i,size:`sm`,disabled:s,onClick:()=>l(!0),className:`cursor-pointer`,children:a}),(0,O.jsxs)(_,{hideCloseButton:!0,className:`w-[28rem] max-w-[calc(100vw-2rem)]`,children:[(0,O.jsxs)(p,{children:[(0,O.jsx)(h,{children:e}),(0,O.jsx)(m,{className:`mt-2`,children:t})]}),(0,O.jsxs)(g,{className:`mt-6 flex justify-end gap-3`,children:[(0,O.jsx)(S,{variant:`outline`,size:`sm`,className:`cursor-pointer`,onClick:()=>l(!1),children:`Cancel`}),(0,O.jsx)(S,{variant:r===`danger`?`danger`:`primary`,size:`sm`,className:`cursor-pointer`,onClick:()=>{o(),l(!1)},children:n})]})]})]})}var A=n(function(){return(0,O.jsx)(T,{title:`Failed to load job`,backTo:{href:`/queues`,label:`Back to Queues`}})}),j=e(function({loaderData:e}){let{job:t,queueName:n}=e,r=o(),i=r.state!==`idle`,[u,f]=(0,D.useState)(!1),p=r.data,m=p&&!p.success&&p.affected===0,h=e=>{r.submit({intent:e},{method:`post`})},g=async()=>{await navigator.clipboard.writeText(t.id),f(!0),setTimeout(()=>f(!1),2e3)},_=t.state===`failed`;return(0,O.jsxs)(`div`,{className:`space-y-4`,children:[(0,O.jsx)(C,{title:(0,O.jsxs)(`span`,{className:`inline-flex items-center gap-3`,children:[`Job detail`,(0,O.jsx)(w,{variant:l[t.state],size:`lg`,dot:!0,children:t.state})]}),action:(0,O.jsxs)(`div`,{className:`flex items-center gap-2`,children:[m&&(0,O.jsx)(`span`,{className:`text-xs text-[var(--warning-600)]`,title:p.message,children:`Action failed`}),t.state===`failed`&&(0,O.jsx)(S,{variant:`outline`,size:`sm`,disabled:i,onClick:()=>h(`retry`),children:`Retry`}),t.state===`cancelled`&&(0,O.jsx)(S,{variant:`outline`,size:`sm`,disabled:i,onClick:()=>h(`resume`),children:`Resume`}),(t.state===`created`||t.state===`retry`||t.state===`active`)&&(0,O.jsx)(k,{title:`Cancel Job`,description:`Are you sure you want to cancel job ${t.id.slice(0,8)}...? This will prevent the job from being processed.`,confirmLabel:`Cancel Job`,confirmVariant:`danger`,triggerVariant:`outline`,trigger:`Cancel`,onConfirm:()=>h(`cancel`),disabled:i}),t.state!==`active`&&(0,O.jsx)(k,{title:`Delete Job`,description:`Are you sure you want to delete job ${t.id.slice(0,8)}...? This action cannot be undone.`,confirmLabel:`Delete`,confirmVariant:`danger`,triggerVariant:`danger`,trigger:`Delete`,onConfirm:()=>h(`delete`),disabled:i})]})}),(0,O.jsxs)(b,{children:[(0,O.jsxs)(y,{children:[(0,O.jsx)(v,{children:`Details`}),(0,O.jsxs)(`span`,{className:`text-xs text-[var(--text-tertiary)]`,children:[`in queue`,` `,(0,O.jsx)(c,{to:`/queues/${encodeURIComponent(n)}`,className:`font-mono text-xs text-primary-600 hover:text-primary-700 dark:text-primary-400 dark:hover:text-primary-300`,children:n})]})]}),(0,O.jsxs)(x,{className:`space-y-6`,children:[(0,O.jsxs)(`div`,{className:`grid grid-cols-1 sm:grid-cols-[2fr_1fr_1fr] gap-6`,children:[(0,O.jsxs)(`div`,{children:[(0,O.jsx)(`div`,{className:`pgb-eyebrow mb-1`,children:`Job ID`}),(0,O.jsxs)(`div`,{className:`flex items-center gap-1.5`,children:[(0,O.jsx)(`code`,{className:`text-sm font-mono break-all text-[var(--text-primary)]`,children:t.id}),(0,O.jsx)(`button`,{onClick:g,className:s(`p-1 rounded-md transition-colors cursor-pointer flex-shrink-0`,`text-[var(--text-tertiary)] hover:text-[var(--text-primary)] hover:bg-[var(--surface-hover)]`),title:u?`Copied!`:`Copy to clipboard`,children:u?(0,O.jsx)(d,{className:`h-4 w-4 text-[var(--success-600)]`}):(0,O.jsx)(E,{className:`h-4 w-4`})})]})]}),(0,O.jsx)(M,{label:`Policy`,value:t.policy||`—`}),(0,O.jsx)(M,{label:`Priority`,value:t.priority,mono:!0})]}),(0,O.jsxs)(`div`,{className:`grid grid-cols-1 lg:grid-cols-2 gap-4`,children:[(0,O.jsxs)(`div`,{children:[(0,O.jsx)(`div`,{className:`pgb-eyebrow mb-1.5`,children:`Data`}),(0,O.jsx)(`pre`,{className:`text-xs px-3.5 py-3 rounded-lg border border-[var(--border-default)] bg-[var(--surface-sunken)] font-mono leading-relaxed text-[var(--text-primary)] overflow-auto max-h-40`,children:t.data?JSON.stringify(t.data,null,2):`null`})]}),(0,O.jsxs)(`div`,{children:[(0,O.jsx)(`div`,{className:`pgb-eyebrow mb-1.5`,children:`Output`}),(0,O.jsx)(`pre`,{className:s(`text-xs px-3.5 py-3 rounded-lg border font-mono leading-relaxed text-[var(--text-primary)] overflow-auto max-h-40`,_?`border-[var(--error-100)] bg-[var(--error-50)]`:`border-[var(--border-default)] bg-[var(--surface-sunken)]`),children:t.output!==void 0&&t.output!==null?JSON.stringify(t.output,null,2):`—`})]})]}),(0,O.jsx)(`div`,{children:(0,O.jsxs)(`div`,{className:`space-y-6`,children:[(0,O.jsx)(`div`,{className:`grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-x-6 gap-y-4`,children:(0,O.jsx)(M,{label:`Priority`,value:t.priority})}),(0,O.jsxs)(`div`,{className:`grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-x-6 gap-y-4`,children:[(0,O.jsx)(M,{label:`Retry Count`,value:t.retryCount,mono:!0}),(0,O.jsx)(M,{label:`Retry Limit`,value:t.retryLimit,mono:!0}),(0,O.jsx)(M,{label:`Retry Delay`,value:t.retryDelay?`${t.retryDelay}ms`:`—`,mono:!0}),(0,O.jsx)(M,{label:`Retry Backoff`,value:t.retryBackoff?`Enabled`:`Disabled`})]}),(t.singletonKey||t.groupId||t.groupTier||t.deadLetter)&&(0,O.jsxs)(`div`,{className:`grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-x-6 gap-y-4`,children:[t.singletonKey&&(0,O.jsx)(M,{label:`Singleton Key`,value:t.singletonKey,mono:!0}),t.groupId&&(0,O.jsx)(M,{label:`Group ID`,value:t.groupId,mono:!0}),t.groupTier&&(0,O.jsx)(M,{label:`Group Tier`,value:t.groupTier,mono:!0}),t.deadLetter&&(0,O.jsxs)(`div`,{children:[(0,O.jsx)(`dt`,{className:`pgb-eyebrow`,children:`Dead Letter`}),(0,O.jsx)(`dd`,{className:`mt-1 text-sm text-[var(--text-primary)]`,children:(0,O.jsx)(c,{to:`/queues/${t.deadLetter}`,className:`font-mono text-xs text-primary-600 hover:text-primary-700 dark:text-primary-400 dark:hover:text-primary-300`,children:t.deadLetter})})]})]}),(t.sourceName||t.sourceId)&&(0,O.jsxs)(`div`,{className:`grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-x-6 gap-y-4`,children:[t.sourceName&&(0,O.jsxs)(`div`,{children:[(0,O.jsx)(`dt`,{className:`pgb-eyebrow`,children:`Source Queue`}),(0,O.jsx)(`dd`,{className:`mt-1 text-sm text-[var(--text-primary)]`,children:(0,O.jsx)(c,{to:`/queues/${t.sourceName}`,className:`font-mono text-xs text-primary-600 hover:text-primary-700 dark:text-primary-400 dark:hover:text-primary-300`,children:t.sourceName})})]}),t.sourceId&&(0,O.jsx)(M,{label:`Source Job ID`,value:t.sourceId,mono:!0}),t.sourceRetryCount!==null&&t.sourceRetryCount!==void 0&&(0,O.jsx)(M,{label:`Source Retry Count`,value:t.sourceRetryCount,mono:!0}),t.sourceCreatedOn&&(0,O.jsx)(M,{label:`Source Created`,value:a(new Date(t.sourceCreatedOn)),mono:!0})]}),(0,O.jsxs)(`div`,{className:`grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-5 gap-x-6 gap-y-4`,children:[(0,O.jsx)(M,{label:`Created`,value:a(new Date(t.createdOn)),mono:!0}),(0,O.jsx)(M,{label:`Start After`,value:t.startAfter?a(new Date(t.startAfter)):`—`,mono:!0}),(0,O.jsx)(M,{label:`Started`,value:t.startedOn?a(new Date(t.startedOn)):`—`,mono:!0}),(0,O.jsx)(M,{label:`Completed`,value:t.completedOn?a(new Date(t.completedOn)):`—`,mono:!0}),(0,O.jsx)(M,{label:`Keep Until`,value:t.keepUntil?a(new Date(t.keepUntil)):`—`,mono:!0})]})]})})]})]})]})});function M({label:e,value:t,mono:n=!1}){return(0,O.jsxs)(`div`,{children:[(0,O.jsx)(`dt`,{className:`pgb-eyebrow`,children:e}),(0,O.jsx)(`dd`,{className:s(`mt-1 text-sm text-[var(--text-primary)]`,n&&`pgb-num`),children:t?.toString()||`—`})]})}export{A as ErrorBoundary,j as default};
|
package/build/server/index.js
CHANGED
|
@@ -1568,7 +1568,8 @@ function createTableVersion(schema) {
|
|
|
1568
1568
|
CREATE TABLE ${schema}.version (
|
|
1569
1569
|
version int primary key,
|
|
1570
1570
|
cron_on timestamp with time zone,
|
|
1571
|
-
bam_on timestamp with time zone
|
|
1571
|
+
bam_on timestamp with time zone,
|
|
1572
|
+
flow_on timestamp with time zone
|
|
1572
1573
|
)
|
|
1573
1574
|
`;
|
|
1574
1575
|
}
|
|
@@ -1798,7 +1799,11 @@ function createTableJob(schema, noPartitioning = false) {
|
|
|
1798
1799
|
heartbeat_seconds int,
|
|
1799
1800
|
blocked boolean not null default false,
|
|
1800
1801
|
blocking boolean not null default false,
|
|
1801
|
-
pending_dependencies int not null default 0
|
|
1802
|
+
pending_dependencies int not null default 0,
|
|
1803
|
+
source_name text,
|
|
1804
|
+
source_id uuid,
|
|
1805
|
+
source_created_on timestamp with time zone,
|
|
1806
|
+
source_retry_count int
|
|
1802
1807
|
) ${partitionClause}
|
|
1803
1808
|
`;
|
|
1804
1809
|
}
|
|
@@ -1825,7 +1830,11 @@ var JOB_COLUMNS_ALL = `${JOB_COLUMNS_MIN},
|
|
|
1825
1830
|
blocked,
|
|
1826
1831
|
blocking,
|
|
1827
1832
|
pending_dependencies as "pendingDependencies",
|
|
1828
|
-
output
|
|
1833
|
+
output,
|
|
1834
|
+
source_name as "sourceName",
|
|
1835
|
+
source_id as "sourceId",
|
|
1836
|
+
source_created_on as "sourceCreatedOn",
|
|
1837
|
+
source_retry_count as "sourceRetryCount"
|
|
1829
1838
|
`;
|
|
1830
1839
|
function createTableJobCommon(schema) {
|
|
1831
1840
|
return `
|
|
@@ -1843,6 +1852,7 @@ function createTableJobCommon(schema) {
|
|
|
1843
1852
|
SELECT ${schema}.job_table_run($cmd$${createIndexJobThrottle(schema)}$cmd$, '${COMMON_JOB_TABLE}');
|
|
1844
1853
|
SELECT ${schema}.job_table_run($cmd$${createIndexJobFetch(schema)}$cmd$, '${COMMON_JOB_TABLE}');
|
|
1845
1854
|
SELECT ${schema}.job_table_run($cmd$${createIndexJobGroupConcurrency(schema)}$cmd$, '${COMMON_JOB_TABLE}');
|
|
1855
|
+
SELECT ${schema}.job_table_run($cmd$${createIndexJobBlocking(schema)}$cmd$, '${COMMON_JOB_TABLE}');
|
|
1846
1856
|
|
|
1847
1857
|
ALTER TABLE ${schema}.job ATTACH PARTITION ${schema}.${COMMON_JOB_TABLE} DEFAULT;
|
|
1848
1858
|
`;
|
|
@@ -1860,6 +1870,7 @@ function createTableJobIndexes(schema, noDeferrableConstraints = false, noCoveri
|
|
|
1860
1870
|
${createIndexJobThrottle(schema)};
|
|
1861
1871
|
${createIndexJobFetch(schema, noCoveringIndex)};
|
|
1862
1872
|
${createIndexJobGroupConcurrency(schema)};
|
|
1873
|
+
${createIndexJobBlocking(schema)};
|
|
1863
1874
|
`;
|
|
1864
1875
|
}
|
|
1865
1876
|
function createQueueFunction(schema, noPartitioning = false) {
|
|
@@ -1970,6 +1981,7 @@ function createQueueFunction(schema, noPartitioning = false) {
|
|
|
1970
1981
|
EXECUTE ${schema}.job_table_format($cmd$${createIndexJobFetch(schema)}$cmd$, tablename);
|
|
1971
1982
|
EXECUTE ${schema}.job_table_format($cmd$${createIndexJobThrottle(schema)}$cmd$, tablename);
|
|
1972
1983
|
EXECUTE ${schema}.job_table_format($cmd$${createIndexJobGroupConcurrency(schema)}$cmd$, tablename);
|
|
1984
|
+
EXECUTE ${schema}.job_table_format($cmd$${createIndexJobBlocking(schema)}$cmd$, tablename);
|
|
1973
1985
|
|
|
1974
1986
|
IF options->>'policy' = 'short' THEN
|
|
1975
1987
|
EXECUTE ${schema}.job_table_format($cmd$${createIndexJobPolicyShort(schema)}$cmd$, tablename);
|
|
@@ -2053,7 +2065,7 @@ function createIndexJobThrottle(schema) {
|
|
|
2053
2065
|
return `CREATE UNIQUE INDEX job_i4 ON ${schema}.job (name, singleton_on, COALESCE(singleton_key, '')) WHERE state <> '${JOB_STATES.cancelled}' AND singleton_on IS NOT NULL`;
|
|
2054
2066
|
}
|
|
2055
2067
|
function createIndexJobFetch(schema, noCoveringIndex = false) {
|
|
2056
|
-
return `CREATE INDEX job_i5 ON ${schema}.job (name, start_after)
|
|
2068
|
+
return `CREATE INDEX job_i5 ON ${schema}.job (name, start_after) WHERE state < '${JOB_STATES.active}' AND NOT blocked`;
|
|
2057
2069
|
}
|
|
2058
2070
|
function createIndexJobPolicyExclusive(schema) {
|
|
2059
2071
|
return `CREATE UNIQUE INDEX job_i6 ON ${schema}.job (name, COALESCE(singleton_key, '')) WHERE state <= '${JOB_STATES.active}' AND policy = '${QUEUE_POLICIES.exclusive}'`;
|
|
@@ -2067,6 +2079,9 @@ function createCheckConstraintKeyStrictFifo(schema) {
|
|
|
2067
2079
|
function createIndexJobGroupConcurrency(schema) {
|
|
2068
2080
|
return `CREATE INDEX job_i7 ON ${schema}.job (name, group_id) WHERE state = '${JOB_STATES.active}' AND group_id IS NOT NULL`;
|
|
2069
2081
|
}
|
|
2082
|
+
function createIndexJobBlocking(schema) {
|
|
2083
|
+
return `CREATE INDEX job_i9 ON ${schema}.job (name, id) WHERE blocking AND state = '${JOB_STATES.completed}'`;
|
|
2084
|
+
}
|
|
2070
2085
|
function trySetQueueMonitorTime(schema, queues, seconds) {
|
|
2071
2086
|
return trySetQueueTimestamp(schema, queues, "monitor_on", seconds);
|
|
2072
2087
|
}
|
|
@@ -2079,6 +2094,9 @@ function trySetCronTime(schema, seconds) {
|
|
|
2079
2094
|
function trySetBamTime(schema, seconds) {
|
|
2080
2095
|
return trySetTimestamp(schema, "bam_on", seconds);
|
|
2081
2096
|
}
|
|
2097
|
+
function trySetFlowTime(schema, seconds) {
|
|
2098
|
+
return trySetTimestamp(schema, "flow_on", seconds);
|
|
2099
|
+
}
|
|
2082
2100
|
function trySetTimestamp(schema, column, seconds) {
|
|
2083
2101
|
return `
|
|
2084
2102
|
UPDATE ${schema}.version
|
|
@@ -2163,7 +2181,7 @@ function deleteJobsById(schema, table) {
|
|
|
2163
2181
|
WITH results as (
|
|
2164
2182
|
DELETE FROM ${schema}.${table}
|
|
2165
2183
|
WHERE name = $1
|
|
2166
|
-
AND id
|
|
2184
|
+
AND id = ANY($2::uuid[])
|
|
2167
2185
|
RETURNING 1
|
|
2168
2186
|
)
|
|
2169
2187
|
SELECT COUNT(*) from results
|
|
@@ -2426,7 +2444,7 @@ function completeJobsUpdate(schema, table, includeQueued) {
|
|
|
2426
2444
|
blocked = ${includeQueued ? "false" : "blocked"},
|
|
2427
2445
|
pending_dependencies = ${includeQueued ? "0" : "pending_dependencies"}
|
|
2428
2446
|
WHERE name = $1
|
|
2429
|
-
AND id
|
|
2447
|
+
AND id = ANY($2::uuid[])
|
|
2430
2448
|
AND ${includeQueued ? `state < '${JOB_STATES.completed}'` : `state = '${JOB_STATES.active}'`}`;
|
|
2431
2449
|
}
|
|
2432
2450
|
function lockedChildrenCte(schema) {
|
|
@@ -2450,24 +2468,11 @@ function unblockChildrenUpdate(schema) {
|
|
|
2450
2468
|
}
|
|
2451
2469
|
function completeJobs(schema, table, includeQueued) {
|
|
2452
2470
|
return `
|
|
2453
|
-
WITH
|
|
2471
|
+
WITH results AS (
|
|
2454
2472
|
${completeJobsUpdate(schema, table, includeQueued)}
|
|
2455
|
-
RETURNING name, id, blocking
|
|
2456
|
-
),
|
|
2457
|
-
decremented AS (
|
|
2458
|
-
SELECT d.child_name, d.child_id, COUNT(*)::int AS n
|
|
2459
|
-
FROM ${schema}.job_dependency d
|
|
2460
|
-
JOIN completed c ON c.blocking
|
|
2461
|
-
AND d.parent_name = c.name
|
|
2462
|
-
AND d.parent_id = c.id
|
|
2463
|
-
GROUP BY d.child_name, d.child_id
|
|
2464
|
-
),
|
|
2465
|
-
${lockedChildrenCte(schema)},
|
|
2466
|
-
unblocked AS (
|
|
2467
|
-
${unblockChildrenUpdate(schema)}
|
|
2468
2473
|
RETURNING 1
|
|
2469
2474
|
)
|
|
2470
|
-
SELECT COUNT(*) FROM
|
|
2475
|
+
SELECT COUNT(*) FROM results
|
|
2471
2476
|
`;
|
|
2472
2477
|
}
|
|
2473
2478
|
function completeJobsWithOutputs(schema, table) {
|
|
@@ -2475,7 +2480,7 @@ function completeJobsWithOutputs(schema, table) {
|
|
|
2475
2480
|
WITH input AS (
|
|
2476
2481
|
SELECT * FROM json_to_recordset($2::json) AS x (id uuid, output jsonb)
|
|
2477
2482
|
),
|
|
2478
|
-
|
|
2483
|
+
results AS (
|
|
2479
2484
|
UPDATE ${schema}.${table} j
|
|
2480
2485
|
SET completed_on = now(),
|
|
2481
2486
|
state = '${JOB_STATES.completed}',
|
|
@@ -2484,22 +2489,9 @@ function completeJobsWithOutputs(schema, table) {
|
|
|
2484
2489
|
WHERE j.name = $1
|
|
2485
2490
|
AND j.id = i.id
|
|
2486
2491
|
AND j.state = '${JOB_STATES.active}'
|
|
2487
|
-
RETURNING j.name, j.id, j.blocking
|
|
2488
|
-
),
|
|
2489
|
-
decremented AS (
|
|
2490
|
-
SELECT d.child_name, d.child_id, COUNT(*)::int AS n
|
|
2491
|
-
FROM ${schema}.job_dependency d
|
|
2492
|
-
JOIN completed c ON c.blocking
|
|
2493
|
-
AND d.parent_name = c.name
|
|
2494
|
-
AND d.parent_id = c.id
|
|
2495
|
-
GROUP BY d.child_name, d.child_id
|
|
2496
|
-
),
|
|
2497
|
-
${lockedChildrenCte(schema)},
|
|
2498
|
-
unblocked AS (
|
|
2499
|
-
${unblockChildrenUpdate(schema)}
|
|
2500
2492
|
RETURNING 1
|
|
2501
2493
|
)
|
|
2502
|
-
SELECT COUNT(*) FROM
|
|
2494
|
+
SELECT COUNT(*) FROM results
|
|
2503
2495
|
`;
|
|
2504
2496
|
}
|
|
2505
2497
|
function completeJobsWithOutputsDistributed(schema, table) {
|
|
@@ -2515,7 +2507,7 @@ function completeJobsWithOutputsDistributed(schema, table) {
|
|
|
2515
2507
|
WHERE j.name = $1
|
|
2516
2508
|
AND j.id = i.id
|
|
2517
2509
|
AND j.state = '${JOB_STATES.active}'
|
|
2518
|
-
RETURNING j.id
|
|
2510
|
+
RETURNING j.id
|
|
2519
2511
|
`;
|
|
2520
2512
|
}
|
|
2521
2513
|
function cancelJobs(schema, table) {
|
|
@@ -2525,7 +2517,7 @@ function cancelJobs(schema, table) {
|
|
|
2525
2517
|
SET completed_on = now(),
|
|
2526
2518
|
state = '${JOB_STATES.cancelled}'
|
|
2527
2519
|
WHERE name = $1
|
|
2528
|
-
AND id
|
|
2520
|
+
AND id = ANY($2::uuid[])
|
|
2529
2521
|
AND state < '${JOB_STATES.completed}'
|
|
2530
2522
|
RETURNING 1
|
|
2531
2523
|
)
|
|
@@ -2539,7 +2531,7 @@ function resumeJobs(schema, table) {
|
|
|
2539
2531
|
SET completed_on = NULL,
|
|
2540
2532
|
state = '${JOB_STATES.created}'
|
|
2541
2533
|
WHERE name = $1
|
|
2542
|
-
AND id
|
|
2534
|
+
AND id = ANY($2::uuid[])
|
|
2543
2535
|
AND state = '${JOB_STATES.cancelled}'
|
|
2544
2536
|
RETURNING 1
|
|
2545
2537
|
)
|
|
@@ -2553,7 +2545,7 @@ function restoreJobs(schema, table) {
|
|
|
2553
2545
|
started_on = NULL,
|
|
2554
2546
|
heartbeat_on = NULL
|
|
2555
2547
|
WHERE name = $1
|
|
2556
|
-
AND id
|
|
2548
|
+
AND id = ANY($2::uuid[])
|
|
2557
2549
|
`;
|
|
2558
2550
|
}
|
|
2559
2551
|
function insertJobs(schema, { table, name, returnId = true, notify = false }) {
|
|
@@ -2668,7 +2660,7 @@ function insertFlowJobs(schema, { table, name }, jobs) {
|
|
|
2668
2660
|
`;
|
|
2669
2661
|
}
|
|
2670
2662
|
function failJobsById(schema, table) {
|
|
2671
|
-
return failJobs(schema, table, `name = $1 AND id
|
|
2663
|
+
return failJobs(schema, table, `name = $1 AND id = ANY($2::uuid[]) AND state < '${JOB_STATES.completed}'`, "$3::jsonb");
|
|
2672
2664
|
}
|
|
2673
2665
|
function failJobsByTimeout(schema, table, queues, noAdvisoryLocks) {
|
|
2674
2666
|
return locked(schema, failJobs(schema, table, `state = '${JOB_STATES.active}'
|
|
@@ -2687,7 +2679,7 @@ function touchJobs(schema, table) {
|
|
|
2687
2679
|
UPDATE ${schema}.${table}
|
|
2688
2680
|
SET heartbeat_on = now()
|
|
2689
2681
|
WHERE name = $1
|
|
2690
|
-
AND id
|
|
2682
|
+
AND id = ANY($2::uuid[])
|
|
2691
2683
|
AND state = '${JOB_STATES.active}'
|
|
2692
2684
|
RETURNING 1
|
|
2693
2685
|
)
|
|
@@ -2856,16 +2848,21 @@ function failJobsBody(schema, table, where, output, forceTerminal = false) {
|
|
|
2856
2848
|
SELECT * FROM failed_jobs
|
|
2857
2849
|
),
|
|
2858
2850
|
dlq_jobs as (
|
|
2859
|
-
INSERT INTO ${schema}.job (name, data, output, retry_limit, retry_backoff, retry_delay, keep_until, deletion_seconds
|
|
2851
|
+
INSERT INTO ${schema}.job (name, data, output, retry_limit, retry_backoff, retry_delay, keep_until, deletion_seconds,
|
|
2852
|
+
source_name, source_id, source_created_on, source_retry_count)
|
|
2860
2853
|
SELECT
|
|
2861
2854
|
r.dead_letter,
|
|
2862
|
-
data,
|
|
2863
|
-
output,
|
|
2855
|
+
r.data,
|
|
2856
|
+
r.output,
|
|
2864
2857
|
q.retry_limit,
|
|
2865
2858
|
q.retry_backoff,
|
|
2866
2859
|
q.retry_delay,
|
|
2867
2860
|
now() + q.retention_seconds * interval '1s',
|
|
2868
|
-
q.deletion_seconds
|
|
2861
|
+
q.deletion_seconds,
|
|
2862
|
+
r.name,
|
|
2863
|
+
r.id,
|
|
2864
|
+
r.created_on,
|
|
2865
|
+
r.retry_count
|
|
2869
2866
|
FROM results r
|
|
2870
2867
|
JOIN ${schema}.queue q ON q.name = r.dead_letter
|
|
2871
2868
|
WHERE state = '${JOB_STATES.failed}'
|
|
@@ -2891,13 +2888,13 @@ function deadLetterJobsByIdWithOutputs(schema, table) {
|
|
|
2891
2888
|
}
|
|
2892
2889
|
function selectJobsToFailById(schema, table) {
|
|
2893
2890
|
return {
|
|
2894
|
-
text: `SELECT * FROM ${schema}.${table} WHERE name = $1 AND id
|
|
2891
|
+
text: `SELECT * FROM ${schema}.${table} WHERE name = $1 AND id = ANY($2::uuid[]) AND state < '${JOB_STATES.completed}'`,
|
|
2895
2892
|
values: []
|
|
2896
2893
|
};
|
|
2897
2894
|
}
|
|
2898
2895
|
function deleteJobsToFail(schema, table) {
|
|
2899
2896
|
return {
|
|
2900
|
-
text: `DELETE FROM ${schema}.${table} WHERE name = $1 AND id
|
|
2897
|
+
text: `DELETE FROM ${schema}.${table} WHERE name = $1 AND id = ANY($2::uuid[])`,
|
|
2901
2898
|
values: []
|
|
2902
2899
|
};
|
|
2903
2900
|
}
|
|
@@ -2922,14 +2919,14 @@ function selectJobsToFailByHeartbeat(schema, table, queues) {
|
|
|
2922
2919
|
}
|
|
2923
2920
|
function deleteJobsByIds(schema, table) {
|
|
2924
2921
|
return {
|
|
2925
|
-
text: `DELETE FROM ${schema}.${table} WHERE id
|
|
2922
|
+
text: `DELETE FROM ${schema}.${table} WHERE id = ANY($1::uuid[])`,
|
|
2926
2923
|
values: []
|
|
2927
2924
|
};
|
|
2928
2925
|
}
|
|
2929
2926
|
function completeJobsDistributed(schema, table, includeQueued) {
|
|
2930
2927
|
return `
|
|
2931
2928
|
${completeJobsUpdate(schema, table, includeQueued)}
|
|
2932
|
-
RETURNING id
|
|
2929
|
+
RETURNING id
|
|
2933
2930
|
`;
|
|
2934
2931
|
}
|
|
2935
2932
|
function decrementDependents(schema) {
|
|
@@ -2938,13 +2935,75 @@ function decrementDependents(schema) {
|
|
|
2938
2935
|
SELECT d.child_name, d.child_id, COUNT(*)::int AS n
|
|
2939
2936
|
FROM ${schema}.job_dependency d
|
|
2940
2937
|
WHERE d.parent_name = $1
|
|
2941
|
-
AND d.parent_id
|
|
2938
|
+
AND d.parent_id = ANY($2::uuid[])
|
|
2942
2939
|
GROUP BY d.child_name, d.child_id
|
|
2943
2940
|
),
|
|
2944
2941
|
${lockedChildrenCte(schema)}
|
|
2945
2942
|
${unblockChildrenUpdate(schema)}
|
|
2946
2943
|
`;
|
|
2947
2944
|
}
|
|
2945
|
+
var FLOW_BATCH_SIZE = 1e3;
|
|
2946
|
+
function resolveFlowJobs(schema, table, names) {
|
|
2947
|
+
return {
|
|
2948
|
+
text: `
|
|
2949
|
+
WITH locked_parents AS (
|
|
2950
|
+
SELECT j.name, j.id
|
|
2951
|
+
FROM ${schema}.${table} j
|
|
2952
|
+
WHERE j.blocking
|
|
2953
|
+
AND j.state = '${JOB_STATES.completed}'
|
|
2954
|
+
AND j.name = ANY($1::text[])
|
|
2955
|
+
ORDER BY j.name, j.id
|
|
2956
|
+
FOR UPDATE OF j SKIP LOCKED
|
|
2957
|
+
LIMIT ${FLOW_BATCH_SIZE}
|
|
2958
|
+
),
|
|
2959
|
+
decremented AS (
|
|
2960
|
+
SELECT d.child_name, d.child_id, COUNT(*)::int AS n
|
|
2961
|
+
FROM ${schema}.job_dependency d
|
|
2962
|
+
JOIN locked_parents p ON d.parent_name = p.name
|
|
2963
|
+
AND d.parent_id = p.id
|
|
2964
|
+
GROUP BY d.child_name, d.child_id
|
|
2965
|
+
),
|
|
2966
|
+
${lockedChildrenCte(schema)},
|
|
2967
|
+
unblocked AS (
|
|
2968
|
+
${unblockChildrenUpdate(schema)}
|
|
2969
|
+
RETURNING 1
|
|
2970
|
+
),
|
|
2971
|
+
cleared AS (
|
|
2972
|
+
UPDATE ${schema}.${table} j
|
|
2973
|
+
SET blocking = false
|
|
2974
|
+
FROM locked_parents p
|
|
2975
|
+
WHERE j.name = p.name
|
|
2976
|
+
AND j.id = p.id
|
|
2977
|
+
RETURNING 1
|
|
2978
|
+
)
|
|
2979
|
+
SELECT COUNT(*)::int AS resolved FROM cleared
|
|
2980
|
+
`,
|
|
2981
|
+
values: [names]
|
|
2982
|
+
};
|
|
2983
|
+
}
|
|
2984
|
+
function selectBlockingParents(schema, table, names, noSkipLocked) {
|
|
2985
|
+
return {
|
|
2986
|
+
text: `
|
|
2987
|
+
SELECT name, id
|
|
2988
|
+
FROM ${schema}.${table}
|
|
2989
|
+
WHERE blocking
|
|
2990
|
+
AND state = '${JOB_STATES.completed}'
|
|
2991
|
+
AND name = ANY($1::text[])
|
|
2992
|
+
ORDER BY name, id
|
|
2993
|
+
FOR UPDATE${noSkipLocked ? "" : " SKIP LOCKED"}
|
|
2994
|
+
LIMIT ${FLOW_BATCH_SIZE}
|
|
2995
|
+
`,
|
|
2996
|
+
values: [names]
|
|
2997
|
+
};
|
|
2998
|
+
}
|
|
2999
|
+
function clearBlocking(schema) {
|
|
3000
|
+
return `
|
|
3001
|
+
UPDATE ${schema}.job
|
|
3002
|
+
SET blocking = false
|
|
3003
|
+
WHERE name = $1
|
|
3004
|
+
AND id = ANY($2::uuid[])
|
|
3005
|
+
`;
|
|
3006
|
+
}
|
|
2948
3007
|
function insertRetryJob(schema, table) {
|
|
2949
3008
|
return `
|
|
2950
3009
|
INSERT INTO ${schema}.${table} (
|
|
@@ -2962,11 +3021,44 @@ function insertRetryJob(schema, table) {
|
|
|
2962
3021
|
}
|
|
2963
3022
|
function insertDeadLetterJob(schema) {
|
|
2964
3023
|
return `
|
|
2965
|
-
INSERT INTO ${schema}.job (name, data, output, retry_limit, retry_backoff, retry_delay, keep_until, deletion_seconds
|
|
2966
|
-
|
|
3024
|
+
INSERT INTO ${schema}.job (name, data, output, retry_limit, retry_backoff, retry_delay, keep_until, deletion_seconds,
|
|
3025
|
+
source_name, source_id, source_created_on, source_retry_count)
|
|
3026
|
+
SELECT $1, $2, $3, q.retry_limit, q.retry_backoff, q.retry_delay, now() + q.retention_seconds * interval '1s', q.deletion_seconds,
|
|
3027
|
+
$4, $5, $6, $7
|
|
2967
3028
|
FROM ${schema}.queue q WHERE q.name = $1
|
|
2968
3029
|
`;
|
|
2969
3030
|
}
|
|
3031
|
+
function redriveJobs(schema, table) {
|
|
3032
|
+
return `
|
|
3033
|
+
WITH candidates AS (
|
|
3034
|
+
SELECT j.id
|
|
3035
|
+
FROM ${schema}.${table} j
|
|
3036
|
+
JOIN ${schema}.queue q ON q.name = COALESCE($2, j.source_name)
|
|
3037
|
+
WHERE j.name = $1
|
|
3038
|
+
AND j.state < '${JOB_STATES.active}'
|
|
3039
|
+
AND ($3::text IS NULL OR j.source_name = $3)
|
|
3040
|
+
ORDER BY j.created_on
|
|
3041
|
+
LIMIT $4
|
|
3042
|
+
FOR UPDATE OF j SKIP LOCKED
|
|
3043
|
+
),
|
|
3044
|
+
moved AS (
|
|
3045
|
+
DELETE FROM ${schema}.${table}
|
|
3046
|
+
WHERE id IN (SELECT id FROM candidates)
|
|
3047
|
+
RETURNING *
|
|
3048
|
+
),
|
|
3049
|
+
ins AS (
|
|
3050
|
+
INSERT INTO ${schema}.job
|
|
3051
|
+
(name, data, priority, retry_limit, retry_backoff, retry_delay, retry_delay_max,
|
|
3052
|
+
expire_seconds, keep_until, deletion_seconds, policy)
|
|
3053
|
+
SELECT COALESCE($2, m.source_name), m.data, m.priority, q.retry_limit, q.retry_backoff,
|
|
3054
|
+
q.retry_delay, q.retry_delay_max, q.expire_seconds,
|
|
3055
|
+
now() + q.retention_seconds * interval '1s', q.deletion_seconds, q.policy
|
|
3056
|
+
FROM moved m JOIN ${schema}.queue q ON q.name = COALESCE($2, m.source_name)
|
|
3057
|
+
RETURNING 1
|
|
3058
|
+
)
|
|
3059
|
+
SELECT count(*)::int AS moved FROM ins
|
|
3060
|
+
`;
|
|
3061
|
+
}
|
|
2970
3062
|
function deletion(schema, table, queues, noAdvisoryLocks) {
|
|
2971
3063
|
return locked(schema, `
|
|
2972
3064
|
DELETE FROM ${schema}.${table}
|
|
@@ -2986,7 +3078,7 @@ function retryJobs(schema, table) {
|
|
|
2986
3078
|
SET state = '${JOB_STATES.retry}',
|
|
2987
3079
|
retry_limit = retry_limit + 1
|
|
2988
3080
|
WHERE name = $1
|
|
2989
|
-
AND id
|
|
3081
|
+
AND id = ANY($2::uuid[])
|
|
2990
3082
|
AND state = '${JOB_STATES.failed}'
|
|
2991
3083
|
RETURNING 1
|
|
2992
3084
|
)
|
|
@@ -3464,6 +3556,7 @@ function getConfig(value) {
|
|
|
3464
3556
|
applyOpsConfig(config);
|
|
3465
3557
|
applyScheduleConfig(config);
|
|
3466
3558
|
applyBamConfig(config);
|
|
3559
|
+
applyFlowConfig(config);
|
|
3467
3560
|
validateWarningConfig(config);
|
|
3468
3561
|
return config;
|
|
3469
3562
|
}
|
|
@@ -3566,6 +3659,11 @@ function applyBamConfig(config) {
|
|
|
3566
3659
|
assert(!("bamIntervalSeconds" in config) || config.bamIntervalSeconds >= minInterval, `configuration assert: bamIntervalSeconds must be at least ${minInterval} seconds`);
|
|
3567
3660
|
config.bamIntervalSeconds = config.bamIntervalSeconds || 60;
|
|
3568
3661
|
}
|
|
3662
|
+
function applyFlowConfig(config) {
|
|
3663
|
+
const minInterval = config.__test__bypass_flow_interval_check ? .5 : 1;
|
|
3664
|
+
assert(!("flowIntervalSeconds" in config) || config.flowIntervalSeconds >= minInterval, `configuration assert: flowIntervalSeconds must be at least ${minInterval} seconds`);
|
|
3665
|
+
config.flowIntervalSeconds = config.flowIntervalSeconds || 5;
|
|
3666
|
+
}
|
|
3569
3667
|
//#endregion
|
|
3570
3668
|
//#region ../../src/migrationStore.ts
|
|
3571
3669
|
function formatJobTable(command, table) {
|
|
@@ -4113,6 +4211,92 @@ var createQueueFn = {
|
|
|
4113
4211
|
END;
|
|
4114
4212
|
$$
|
|
4115
4213
|
LANGUAGE plpgsql;
|
|
4214
|
+
`,
|
|
4215
|
+
33: (schema) => `
|
|
4216
|
+
CREATE OR REPLACE FUNCTION ${schema}.create_queue(queue_name text, options jsonb)
|
|
4217
|
+
RETURNS VOID AS
|
|
4218
|
+
$$
|
|
4219
|
+
DECLARE
|
|
4220
|
+
tablename varchar := CASE WHEN options->>'partition' = 'true'
|
|
4221
|
+
THEN 'j' || encode(sha224(queue_name::bytea), 'hex')
|
|
4222
|
+
ELSE 'job_common'
|
|
4223
|
+
END;
|
|
4224
|
+
queue_created_on timestamptz;
|
|
4225
|
+
BEGIN
|
|
4226
|
+
|
|
4227
|
+
WITH q as (
|
|
4228
|
+
INSERT INTO ${schema}.queue (
|
|
4229
|
+
name,
|
|
4230
|
+
policy,
|
|
4231
|
+
retry_limit,
|
|
4232
|
+
retry_delay,
|
|
4233
|
+
retry_backoff,
|
|
4234
|
+
retry_delay_max,
|
|
4235
|
+
expire_seconds,
|
|
4236
|
+
retention_seconds,
|
|
4237
|
+
deletion_seconds,
|
|
4238
|
+
warning_queued,
|
|
4239
|
+
dead_letter,
|
|
4240
|
+
partition,
|
|
4241
|
+
table_name,
|
|
4242
|
+
heartbeat_seconds,
|
|
4243
|
+
notify
|
|
4244
|
+
)
|
|
4245
|
+
VALUES (
|
|
4246
|
+
queue_name,
|
|
4247
|
+
options->>'policy',
|
|
4248
|
+
COALESCE((options->>'retryLimit')::int, 2),
|
|
4249
|
+
COALESCE((options->>'retryDelay')::int, 0),
|
|
4250
|
+
COALESCE((options->>'retryBackoff')::bool, false),
|
|
4251
|
+
(options->>'retryDelayMax')::int,
|
|
4252
|
+
COALESCE((options->>'expireInSeconds')::int, 900),
|
|
4253
|
+
COALESCE((options->>'retentionSeconds')::int, 1209600),
|
|
4254
|
+
COALESCE((options->>'deleteAfterSeconds')::int, 604800),
|
|
4255
|
+
COALESCE((options->>'warningQueueSize')::int, 0),
|
|
4256
|
+
options->>'deadLetter',
|
|
4257
|
+
COALESCE((options->>'partition')::bool, false),
|
|
4258
|
+
tablename,
|
|
4259
|
+
(options->>'heartbeatSeconds')::int,
|
|
4260
|
+
COALESCE((options->>'notify')::bool, false)
|
|
4261
|
+
)
|
|
4262
|
+
ON CONFLICT DO NOTHING
|
|
4263
|
+
RETURNING created_on
|
|
4264
|
+
)
|
|
4265
|
+
SELECT created_on into queue_created_on from q;
|
|
4266
|
+
|
|
4267
|
+
IF queue_created_on IS NULL OR options->>'partition' IS DISTINCT FROM 'true' THEN
|
|
4268
|
+
RETURN;
|
|
4269
|
+
END IF;
|
|
4270
|
+
|
|
4271
|
+
EXECUTE format('CREATE TABLE ${schema}.%I (LIKE ${schema}.job INCLUDING DEFAULTS)', tablename);
|
|
4272
|
+
|
|
4273
|
+
EXECUTE ${schema}.job_table_format($cmd$ALTER TABLE ${schema}.job ADD PRIMARY KEY (name, id)$cmd$, tablename);
|
|
4274
|
+
EXECUTE ${schema}.job_table_format($cmd$ALTER TABLE ${schema}.job ADD CONSTRAINT q_fkey FOREIGN KEY (name) REFERENCES ${schema}.queue (name) ON DELETE RESTRICT DEFERRABLE INITIALLY DEFERRED$cmd$, tablename);
|
|
4275
|
+
EXECUTE ${schema}.job_table_format($cmd$ALTER TABLE ${schema}.job ADD CONSTRAINT dlq_fkey FOREIGN KEY (dead_letter) REFERENCES ${schema}.queue (name) ON DELETE RESTRICT DEFERRABLE INITIALLY DEFERRED$cmd$, tablename);
|
|
4276
|
+
|
|
4277
|
+
EXECUTE ${schema}.job_table_format($cmd$CREATE INDEX job_i5 ON ${schema}.job (name, start_after) WHERE state < 'active' AND NOT blocked$cmd$, tablename);
|
|
4278
|
+
EXECUTE ${schema}.job_table_format($cmd$CREATE UNIQUE INDEX job_i4 ON ${schema}.job (name, singleton_on, COALESCE(singleton_key, '')) WHERE state <> 'cancelled' AND singleton_on IS NOT NULL$cmd$, tablename);
|
|
4279
|
+
EXECUTE ${schema}.job_table_format($cmd$CREATE INDEX job_i7 ON ${schema}.job (name, group_id) WHERE state = 'active' AND group_id IS NOT NULL$cmd$, tablename);
|
|
4280
|
+
EXECUTE ${schema}.job_table_format($cmd$CREATE INDEX job_i9 ON ${schema}.job (name, id) WHERE blocking AND state = 'completed'$cmd$, tablename);
|
|
4281
|
+
|
|
4282
|
+
IF options->>'policy' = 'short' THEN
|
|
4283
|
+
EXECUTE ${schema}.job_table_format($cmd$CREATE UNIQUE INDEX job_i1 ON ${schema}.job (name, COALESCE(singleton_key, '')) WHERE state = 'created' AND policy = 'short'$cmd$, tablename);
|
|
4284
|
+
ELSIF options->>'policy' = 'singleton' THEN
|
|
4285
|
+
EXECUTE ${schema}.job_table_format($cmd$CREATE UNIQUE INDEX job_i2 ON ${schema}.job (name, COALESCE(singleton_key, '')) WHERE state = 'active' AND policy = 'singleton'$cmd$, tablename);
|
|
4286
|
+
ELSIF options->>'policy' = 'stately' THEN
|
|
4287
|
+
EXECUTE ${schema}.job_table_format($cmd$CREATE UNIQUE INDEX job_i3 ON ${schema}.job (name, state, COALESCE(singleton_key, '')) WHERE state <= 'active' AND policy = 'stately'$cmd$, tablename);
|
|
4288
|
+
ELSIF options->>'policy' = 'exclusive' THEN
|
|
4289
|
+
EXECUTE ${schema}.job_table_format($cmd$CREATE UNIQUE INDEX job_i6 ON ${schema}.job (name, COALESCE(singleton_key, '')) WHERE state <= 'active' AND policy = 'exclusive'$cmd$, tablename);
|
|
4290
|
+
ELSIF options->>'policy' = 'key_strict_fifo' THEN
|
|
4291
|
+
EXECUTE ${schema}.job_table_format($cmd$CREATE UNIQUE INDEX job_i8 ON ${schema}.job (name, singleton_key) WHERE state IN ('active', 'retry', 'failed') AND policy = 'key_strict_fifo'$cmd$, tablename);
|
|
4292
|
+
EXECUTE ${schema}.job_table_format($cmd$ALTER TABLE ${schema}.job ADD CONSTRAINT job_key_strict_fifo_singleton_key_check CHECK (NOT (policy = 'key_strict_fifo' AND singleton_key IS NULL))$cmd$, tablename);
|
|
4293
|
+
END IF;
|
|
4294
|
+
|
|
4295
|
+
EXECUTE format('ALTER TABLE ${schema}.%I ADD CONSTRAINT cjc CHECK (name=%L)', tablename, queue_name);
|
|
4296
|
+
EXECUTE format('ALTER TABLE ${schema}.job ATTACH PARTITION ${schema}.%I FOR VALUES IN (%L)', tablename, queue_name);
|
|
4297
|
+
END;
|
|
4298
|
+
$$
|
|
4299
|
+
LANGUAGE plpgsql;
|
|
4116
4300
|
`
|
|
4117
4301
|
};
|
|
4118
4302
|
function getAll(schema) {
|
|
@@ -4361,6 +4545,42 @@ function getAll(schema) {
|
|
|
4361
4545
|
createQueueFn[31](schema),
|
|
4362
4546
|
`ALTER TABLE ${schema}.queue DROP COLUMN notify`
|
|
4363
4547
|
]
|
|
4548
|
+
},
|
|
4549
|
+
{
|
|
4550
|
+
release: "12.22.0",
|
|
4551
|
+
version: 33,
|
|
4552
|
+
previous: 32,
|
|
4553
|
+
install: [
|
|
4554
|
+
`ALTER TABLE ${schema}.version ADD COLUMN IF NOT EXISTS flow_on timestamp with time zone`,
|
|
4555
|
+
`SELECT ${schema}.job_table_run($cmd$CREATE INDEX job_i9 ON ${schema}.job (name, id) WHERE blocking AND state = 'completed'$cmd$)`,
|
|
4556
|
+
`SELECT ${schema}.job_table_run($cmd$DROP INDEX IF EXISTS ${schema}.job_i5$cmd$)`,
|
|
4557
|
+
`SELECT ${schema}.job_table_run($cmd$CREATE INDEX job_i5 ON ${schema}.job (name, start_after) WHERE state < 'active' AND NOT blocked$cmd$)`,
|
|
4558
|
+
createQueueFn[33](schema)
|
|
4559
|
+
],
|
|
4560
|
+
uninstall: [
|
|
4561
|
+
createQueueFn[32](schema),
|
|
4562
|
+
`SELECT ${schema}.job_table_run($cmd$DROP INDEX IF EXISTS ${schema}.job_i5$cmd$)`,
|
|
4563
|
+
`SELECT ${schema}.job_table_run($cmd$CREATE INDEX job_i5 ON ${schema}.job (name, start_after) INCLUDE (priority, created_on, id) WHERE state < 'active' AND NOT blocked$cmd$)`,
|
|
4564
|
+
`SELECT ${schema}.job_table_run($cmd$DROP INDEX IF EXISTS ${schema}.job_i9$cmd$)`,
|
|
4565
|
+
`ALTER TABLE ${schema}.version DROP COLUMN flow_on`
|
|
4566
|
+
]
|
|
4567
|
+
},
|
|
4568
|
+
{
|
|
4569
|
+
release: "12.23.0",
|
|
4570
|
+
version: 34,
|
|
4571
|
+
previous: 33,
|
|
4572
|
+
install: [
|
|
4573
|
+
`ALTER TABLE ${schema}.job ADD COLUMN IF NOT EXISTS source_name text`,
|
|
4574
|
+
`ALTER TABLE ${schema}.job ADD COLUMN IF NOT EXISTS source_id uuid`,
|
|
4575
|
+
`ALTER TABLE ${schema}.job ADD COLUMN IF NOT EXISTS source_created_on timestamp with time zone`,
|
|
4576
|
+
`ALTER TABLE ${schema}.job ADD COLUMN IF NOT EXISTS source_retry_count int`
|
|
4577
|
+
],
|
|
4578
|
+
uninstall: [
|
|
4579
|
+
`ALTER TABLE ${schema}.job DROP COLUMN source_name`,
|
|
4580
|
+
`ALTER TABLE ${schema}.job DROP COLUMN source_id`,
|
|
4581
|
+
`ALTER TABLE ${schema}.job DROP COLUMN source_created_on`,
|
|
4582
|
+
`ALTER TABLE ${schema}.job DROP COLUMN source_retry_count`
|
|
4583
|
+
]
|
|
4364
4584
|
}
|
|
4365
4585
|
];
|
|
4366
4586
|
}
|
|
@@ -4368,7 +4588,7 @@ function getAll(schema) {
|
|
|
4368
4588
|
//#region ../../src/contractor.ts
|
|
4369
4589
|
var schemaVersion = {
|
|
4370
4590
|
name: "pg-boss",
|
|
4371
|
-
version: "12.
|
|
4591
|
+
version: "12.23.0",
|
|
4372
4592
|
description: "Queueing jobs in Postgres from Node.js like a boss",
|
|
4373
4593
|
type: "module",
|
|
4374
4594
|
main: "./dist/index.js",
|
|
@@ -4376,7 +4596,7 @@ var schemaVersion = {
|
|
|
4376
4596
|
bin: { "pg-boss": "./dist/cli.js" },
|
|
4377
4597
|
engines: { "node": ">=22.12.0" },
|
|
4378
4598
|
dependencies: {
|
|
4379
|
-
"cron-parser": "^5.6.
|
|
4599
|
+
"cron-parser": "^5.6.1",
|
|
4380
4600
|
"pg": "^8.22.0",
|
|
4381
4601
|
"serialize-error": "^13.0.1"
|
|
4382
4602
|
},
|
|
@@ -4424,7 +4644,7 @@ var schemaVersion = {
|
|
|
4424
4644
|
"docs": "npm run docs:dev --prefix docs",
|
|
4425
4645
|
"docs:readme": "node ./scripts/sync-readme.js"
|
|
4426
4646
|
},
|
|
4427
|
-
pgboss: { "schema":
|
|
4647
|
+
pgboss: { "schema": 34 },
|
|
4428
4648
|
repository: {
|
|
4429
4649
|
"type": "git",
|
|
4430
4650
|
"url": "git+https://github.com/timgit/pg-boss.git"
|
|
@@ -4938,7 +5158,7 @@ var NUMERIC_QUEUE_FIELDS = [
|
|
|
4938
5158
|
"activeCount",
|
|
4939
5159
|
"totalCount"
|
|
4940
5160
|
];
|
|
4941
|
-
var events$
|
|
5161
|
+
var events$5 = {
|
|
4942
5162
|
error: "error",
|
|
4943
5163
|
wip: "wip"
|
|
4944
5164
|
};
|
|
@@ -4947,7 +5167,7 @@ function rethrowWriteError(err) {
|
|
|
4947
5167
|
throw err;
|
|
4948
5168
|
}
|
|
4949
5169
|
var Manager = class extends EventEmitter {
|
|
4950
|
-
events = events$
|
|
5170
|
+
events = events$5;
|
|
4951
5171
|
db;
|
|
4952
5172
|
config;
|
|
4953
5173
|
wipTs;
|
|
@@ -5110,17 +5330,15 @@ var Manager = class extends EventEmitter {
|
|
|
5110
5330
|
output: this.mapCompletionDataArg(item.output)
|
|
5111
5331
|
}));
|
|
5112
5332
|
const ids = items.map((item) => item.id);
|
|
5113
|
-
if (this.config.noMultiMutationCte)
|
|
5333
|
+
if (this.config.noMultiMutationCte) {
|
|
5114
5334
|
const sql = completeJobsWithOutputsDistributed(this.config.schema, table);
|
|
5115
|
-
const { rows } = await
|
|
5116
|
-
const blockingIds = rows.filter((row) => row.blocking).map((row) => row.id);
|
|
5117
|
-
if (blockingIds.length > 0) await tx.executeSql(decrementDependents(this.config.schema), [name, blockingIds]);
|
|
5335
|
+
const { rows } = await this.db.executeSql(sql, [name, JSON.stringify(payload)]);
|
|
5118
5336
|
return {
|
|
5119
5337
|
jobs: ids,
|
|
5120
5338
|
requested: ids.length,
|
|
5121
5339
|
affected: rows.length
|
|
5122
5340
|
};
|
|
5123
|
-
}
|
|
5341
|
+
}
|
|
5124
5342
|
const sql = completeJobsWithOutputs(this.config.schema, table);
|
|
5125
5343
|
const result = await this.db.executeSql(sql, [name, JSON.stringify(payload)]);
|
|
5126
5344
|
return this.mapCommandResponse(ids, result);
|
|
@@ -5208,7 +5426,7 @@ var Manager = class extends EventEmitter {
|
|
|
5208
5426
|
try {
|
|
5209
5427
|
await this.touch(name, jobIds);
|
|
5210
5428
|
} catch (err) {
|
|
5211
|
-
this.emit(events$
|
|
5429
|
+
this.emit(events$5.error, err);
|
|
5212
5430
|
}
|
|
5213
5431
|
}, intervalMs);
|
|
5214
5432
|
}
|
|
@@ -5245,7 +5463,7 @@ var Manager = class extends EventEmitter {
|
|
|
5245
5463
|
if (now - this.wipTs < 2e3) return;
|
|
5246
5464
|
const wip = this.getWipData();
|
|
5247
5465
|
if (wip.some((w) => w.count > 0)) {
|
|
5248
|
-
this.emit(events$
|
|
5466
|
+
this.emit(events$5.wip, wip);
|
|
5249
5467
|
this.wipTs = now;
|
|
5250
5468
|
}
|
|
5251
5469
|
}, 2e3);
|
|
@@ -5260,7 +5478,7 @@ var Manager = class extends EventEmitter {
|
|
|
5260
5478
|
return acc;
|
|
5261
5479
|
}, {});
|
|
5262
5480
|
} catch (error) {
|
|
5263
|
-
emit && this.emit(events$
|
|
5481
|
+
emit && this.emit(events$5.error, {
|
|
5264
5482
|
...error,
|
|
5265
5483
|
message: error.message,
|
|
5266
5484
|
stack: error.stack
|
|
@@ -5340,7 +5558,7 @@ var Manager = class extends EventEmitter {
|
|
|
5340
5558
|
this.emitWip(name);
|
|
5341
5559
|
};
|
|
5342
5560
|
const onError = (error) => {
|
|
5343
|
-
this.emit(events$
|
|
5561
|
+
this.emit(events$5.error, {
|
|
5344
5562
|
...error,
|
|
5345
5563
|
message: error.message,
|
|
5346
5564
|
stack: error.stack,
|
|
@@ -5379,7 +5597,7 @@ var Manager = class extends EventEmitter {
|
|
|
5379
5597
|
if (!INTERNAL_QUEUES[name]) {
|
|
5380
5598
|
const now = Date.now();
|
|
5381
5599
|
if (now - this.wipTs > 2e3) {
|
|
5382
|
-
this.emit(events$
|
|
5600
|
+
this.emit(events$5.wip, this.getWipData());
|
|
5383
5601
|
this.wipTs = now;
|
|
5384
5602
|
}
|
|
5385
5603
|
}
|
|
@@ -5714,24 +5932,17 @@ var Manager = class extends EventEmitter {
|
|
|
5714
5932
|
return fn(db);
|
|
5715
5933
|
}
|
|
5716
5934
|
async completeDistributed(name, ids, outputData, table, db, includeQueued) {
|
|
5717
|
-
|
|
5718
|
-
|
|
5719
|
-
|
|
5720
|
-
|
|
5721
|
-
|
|
5722
|
-
|
|
5723
|
-
|
|
5724
|
-
|
|
5725
|
-
|
|
5726
|
-
|
|
5727
|
-
|
|
5728
|
-
}
|
|
5729
|
-
return {
|
|
5730
|
-
jobs: ids,
|
|
5731
|
-
requested: ids.length,
|
|
5732
|
-
affected: rows.length
|
|
5733
|
-
};
|
|
5734
|
-
});
|
|
5935
|
+
const sql = completeJobsDistributed(this.config.schema, table, includeQueued);
|
|
5936
|
+
const { rows } = await db.executeSql(sql, [
|
|
5937
|
+
name,
|
|
5938
|
+
ids,
|
|
5939
|
+
outputData
|
|
5940
|
+
]);
|
|
5941
|
+
return {
|
|
5942
|
+
jobs: ids,
|
|
5943
|
+
requested: ids.length,
|
|
5944
|
+
affected: rows.length
|
|
5945
|
+
};
|
|
5735
5946
|
}
|
|
5736
5947
|
async fail(name, id, data, options = {}) {
|
|
5737
5948
|
assertQueueName(name);
|
|
@@ -5775,6 +5986,26 @@ var Manager = class extends EventEmitter {
|
|
|
5775
5986
|
const select = selectJobsToFailByHeartbeat(this.config.schema, table, queues);
|
|
5776
5987
|
return this.expireJobsDistributed(table, select, { value: { message: "job heartbeat timeout" } });
|
|
5777
5988
|
}
|
|
5989
|
+
async resolveFlowJobsDistributed(table, names) {
|
|
5990
|
+
const select = selectBlockingParents(this.config.schema, table, names, this.config.noSkipLocked);
|
|
5991
|
+
return this.withDistributedTransaction(this.db, async (tx) => {
|
|
5992
|
+
const { rows } = await tx.executeSql(select.text, select.values);
|
|
5993
|
+
if (rows.length === 0) return 0;
|
|
5994
|
+
const idsByName = /* @__PURE__ */ new Map();
|
|
5995
|
+
for (const row of rows) {
|
|
5996
|
+
const list = idsByName.get(row.name) || [];
|
|
5997
|
+
list.push(row.id);
|
|
5998
|
+
idsByName.set(row.name, list);
|
|
5999
|
+
}
|
|
6000
|
+
const decrementSql = decrementDependents(this.config.schema);
|
|
6001
|
+
const clearSql = clearBlocking(this.config.schema);
|
|
6002
|
+
for (const [name, ids] of idsByName) {
|
|
6003
|
+
await tx.executeSql(decrementSql, [name, ids]);
|
|
6004
|
+
await tx.executeSql(clearSql, [name, ids]);
|
|
6005
|
+
}
|
|
6006
|
+
return rows.length;
|
|
6007
|
+
});
|
|
6008
|
+
}
|
|
5778
6009
|
async expireJobsDistributed(table, select, outputData) {
|
|
5779
6010
|
return this.withDistributedTransaction(this.db, async (tx) => {
|
|
5780
6011
|
const { rows: jobs } = await tx.executeSql(select.text, []);
|
|
@@ -5874,7 +6105,11 @@ var Manager = class extends EventEmitter {
|
|
|
5874
6105
|
if (job.dead_letter) await tx.executeSql(dlqSql, [
|
|
5875
6106
|
job.dead_letter,
|
|
5876
6107
|
job.data,
|
|
5877
|
-
jobOutput
|
|
6108
|
+
jobOutput,
|
|
6109
|
+
job.name,
|
|
6110
|
+
job.id,
|
|
6111
|
+
job.created_on,
|
|
6112
|
+
job.retry_count
|
|
5878
6113
|
]);
|
|
5879
6114
|
}
|
|
5880
6115
|
count++;
|
|
@@ -5890,6 +6125,22 @@ var Manager = class extends EventEmitter {
|
|
|
5890
6125
|
const result = await db.executeSql(sql, [name, ids]);
|
|
5891
6126
|
return this.mapCommandResponse(ids, result);
|
|
5892
6127
|
}
|
|
6128
|
+
async redrive(name, options = {}) {
|
|
6129
|
+
assertQueueName(name);
|
|
6130
|
+
const { destination, sourceName, limit = 1e3 } = options;
|
|
6131
|
+
if (destination !== void 0) assertQueueName(destination);
|
|
6132
|
+
if (sourceName !== void 0) assertQueueName(sourceName);
|
|
6133
|
+
assert(Number.isInteger(limit) && limit >= 1, "limit must be an integer >= 1");
|
|
6134
|
+
const db = this.assertDb(options);
|
|
6135
|
+
const { table } = await this.getQueueCache(name);
|
|
6136
|
+
const sql = redriveJobs(this.config.schema, table);
|
|
6137
|
+
return (await db.executeSql(sql, [
|
|
6138
|
+
name,
|
|
6139
|
+
destination ?? null,
|
|
6140
|
+
sourceName ?? null,
|
|
6141
|
+
limit
|
|
6142
|
+
])).rows[0].moved;
|
|
6143
|
+
}
|
|
5893
6144
|
async cancel(name, id, options = {}) {
|
|
5894
6145
|
assertQueueName(name);
|
|
5895
6146
|
const db = this.assertDb(options);
|
|
@@ -6099,7 +6350,7 @@ var Manager = class extends EventEmitter {
|
|
|
6099
6350
|
};
|
|
6100
6351
|
//#endregion
|
|
6101
6352
|
//#region ../../src/boss.ts
|
|
6102
|
-
var events$
|
|
6353
|
+
var events$4 = {
|
|
6103
6354
|
error: "error",
|
|
6104
6355
|
warning: "warning"
|
|
6105
6356
|
};
|
|
@@ -6125,7 +6376,7 @@ var Boss = class extends EventEmitter {
|
|
|
6125
6376
|
#db;
|
|
6126
6377
|
#config;
|
|
6127
6378
|
#manager;
|
|
6128
|
-
events = events$
|
|
6379
|
+
events = events$4;
|
|
6129
6380
|
constructor(db, manager, config) {
|
|
6130
6381
|
super();
|
|
6131
6382
|
this.#db = db;
|
|
@@ -6160,8 +6411,8 @@ var Boss = class extends EventEmitter {
|
|
|
6160
6411
|
db: this.#db,
|
|
6161
6412
|
schema: this.#config.schema,
|
|
6162
6413
|
persistWarnings: this.#config.persistWarnings,
|
|
6163
|
-
warningEvent: events$
|
|
6164
|
-
errorEvent: events$
|
|
6414
|
+
warningEvent: events$4.warning,
|
|
6415
|
+
errorEvent: events$4.error
|
|
6165
6416
|
};
|
|
6166
6417
|
}
|
|
6167
6418
|
async #executeQuery(query) {
|
|
@@ -6190,7 +6441,7 @@ var Boss = class extends EventEmitter {
|
|
|
6190
6441
|
!this.#stopped && await this.supervise(queues);
|
|
6191
6442
|
!this.#stopped && await this.#maintainWarnings();
|
|
6192
6443
|
} catch (err) {
|
|
6193
|
-
this.emit(events$
|
|
6444
|
+
this.emit(events$4.error, err);
|
|
6194
6445
|
} finally {
|
|
6195
6446
|
this.#maintaining = false;
|
|
6196
6447
|
}
|
|
@@ -6268,7 +6519,7 @@ var Boss = class extends EventEmitter {
|
|
|
6268
6519
|
};
|
|
6269
6520
|
//#endregion
|
|
6270
6521
|
//#region ../../src/bam.ts
|
|
6271
|
-
var events$
|
|
6522
|
+
var events$3 = {
|
|
6272
6523
|
error: "error",
|
|
6273
6524
|
bam: "bam"
|
|
6274
6525
|
};
|
|
@@ -6278,7 +6529,7 @@ var Bam = class extends EventEmitter {
|
|
|
6278
6529
|
#pollInterval;
|
|
6279
6530
|
#db;
|
|
6280
6531
|
#config;
|
|
6281
|
-
events = events$
|
|
6532
|
+
events = events$3;
|
|
6282
6533
|
constructor(db, config) {
|
|
6283
6534
|
super();
|
|
6284
6535
|
this.#db = db;
|
|
@@ -6314,7 +6565,7 @@ var Bam = class extends EventEmitter {
|
|
|
6314
6565
|
const { rows } = await this.#db.executeSql(sql);
|
|
6315
6566
|
if (rows.length === 1) await this.#processCommands();
|
|
6316
6567
|
} catch (err) {
|
|
6317
|
-
this.emit(events$
|
|
6568
|
+
this.emit(events$3.error, err);
|
|
6318
6569
|
} finally {
|
|
6319
6570
|
this.#working = false;
|
|
6320
6571
|
}
|
|
@@ -6323,7 +6574,7 @@ var Bam = class extends EventEmitter {
|
|
|
6323
6574
|
if (this.#stopped) return;
|
|
6324
6575
|
const entry = await this.#getNextCommand();
|
|
6325
6576
|
if (!entry || this.#stopped) return;
|
|
6326
|
-
this.emit(events$
|
|
6577
|
+
this.emit(events$3.bam, {
|
|
6327
6578
|
id: entry.id,
|
|
6328
6579
|
name: entry.name,
|
|
6329
6580
|
status: "in_progress",
|
|
@@ -6334,7 +6585,7 @@ var Bam = class extends EventEmitter {
|
|
|
6334
6585
|
await this.#db.executeSql(entry.command);
|
|
6335
6586
|
if (this.#stopped) return;
|
|
6336
6587
|
await this.#markCompleted(entry.id);
|
|
6337
|
-
this.emit(events$
|
|
6588
|
+
this.emit(events$3.bam, {
|
|
6338
6589
|
id: entry.id,
|
|
6339
6590
|
name: entry.name,
|
|
6340
6591
|
status: "completed",
|
|
@@ -6344,8 +6595,8 @@ var Bam = class extends EventEmitter {
|
|
|
6344
6595
|
} catch (err) {
|
|
6345
6596
|
if (this.#stopped) return;
|
|
6346
6597
|
await this.#markFailed(entry.id, err);
|
|
6347
|
-
this.emit(events$
|
|
6348
|
-
this.emit(events$
|
|
6598
|
+
this.emit(events$3.error, err);
|
|
6599
|
+
this.emit(events$3.bam, {
|
|
6349
6600
|
id: entry.id,
|
|
6350
6601
|
name: entry.name,
|
|
6351
6602
|
status: "failed",
|
|
@@ -6370,6 +6621,111 @@ var Bam = class extends EventEmitter {
|
|
|
6370
6621
|
}
|
|
6371
6622
|
};
|
|
6372
6623
|
//#endregion
|
|
6624
|
+
//#region ../../src/navigator.ts
|
|
6625
|
+
var events$2 = {
|
|
6626
|
+
error: "error",
|
|
6627
|
+
flow: "flow"
|
|
6628
|
+
};
|
|
6629
|
+
var MAX_BATCHES_PER_PASS = 100;
|
|
6630
|
+
var Navigator = class extends EventEmitter {
|
|
6631
|
+
#stopped;
|
|
6632
|
+
#stopping;
|
|
6633
|
+
#working;
|
|
6634
|
+
#pollInterval;
|
|
6635
|
+
#db;
|
|
6636
|
+
#manager;
|
|
6637
|
+
#config;
|
|
6638
|
+
events = events$2;
|
|
6639
|
+
constructor(db, manager, config) {
|
|
6640
|
+
super();
|
|
6641
|
+
this.#db = db;
|
|
6642
|
+
this.#manager = manager;
|
|
6643
|
+
this.#config = config;
|
|
6644
|
+
this.#stopped = true;
|
|
6645
|
+
this.#stopping = false;
|
|
6646
|
+
this.#working = false;
|
|
6647
|
+
}
|
|
6648
|
+
get working() {
|
|
6649
|
+
return this.#working;
|
|
6650
|
+
}
|
|
6651
|
+
async start() {
|
|
6652
|
+
if (!this.#stopped) return;
|
|
6653
|
+
this.#stopped = false;
|
|
6654
|
+
this.#stopping = false;
|
|
6655
|
+
setImmediate(() => this.#onPoll());
|
|
6656
|
+
this.#pollInterval = setInterval(() => this.#onPoll(), this.#config.flowIntervalSeconds * 1e3);
|
|
6657
|
+
}
|
|
6658
|
+
async stop() {
|
|
6659
|
+
if (this.#stopped) return;
|
|
6660
|
+
this.#stopping = true;
|
|
6661
|
+
this.#stopped = true;
|
|
6662
|
+
if (this.#pollInterval) {
|
|
6663
|
+
clearInterval(this.#pollInterval);
|
|
6664
|
+
this.#pollInterval = void 0;
|
|
6665
|
+
}
|
|
6666
|
+
while (this.#working) await delay(10);
|
|
6667
|
+
}
|
|
6668
|
+
async #onPoll() {
|
|
6669
|
+
if (this.#stopped || this.#working) return;
|
|
6670
|
+
this.#working = true;
|
|
6671
|
+
try {
|
|
6672
|
+
if (this.#config.__test__throw_flow) throw new Error(this.#config.__test__throw_flow);
|
|
6673
|
+
if (this.#config.__test__delay_flow_ms) await delay(this.#config.__test__delay_flow_ms);
|
|
6674
|
+
const gate = trySetFlowTime(this.#config.schema, this.#config.flowIntervalSeconds);
|
|
6675
|
+
const { rows } = await this.#db.executeSql(gate);
|
|
6676
|
+
if (rows.length === 1) await this.#resolve();
|
|
6677
|
+
} catch (err) {
|
|
6678
|
+
this.emit(events$2.error, err);
|
|
6679
|
+
} finally {
|
|
6680
|
+
this.#working = false;
|
|
6681
|
+
}
|
|
6682
|
+
}
|
|
6683
|
+
async resolveNow() {
|
|
6684
|
+
while (this.#working) await delay(10);
|
|
6685
|
+
if (this.#stopping) return;
|
|
6686
|
+
this.#working = true;
|
|
6687
|
+
try {
|
|
6688
|
+
await this.#resolve();
|
|
6689
|
+
} finally {
|
|
6690
|
+
this.#working = false;
|
|
6691
|
+
}
|
|
6692
|
+
}
|
|
6693
|
+
async #resolve() {
|
|
6694
|
+
const queueGroups = (await this.#manager.getQueues()).reduce((acc, q) => {
|
|
6695
|
+
acc[q.table] = acc[q.table] || {
|
|
6696
|
+
table: q.table,
|
|
6697
|
+
names: []
|
|
6698
|
+
};
|
|
6699
|
+
acc[q.table].names.push(q.name);
|
|
6700
|
+
return acc;
|
|
6701
|
+
}, {});
|
|
6702
|
+
for (const group of Object.values(queueGroups)) {
|
|
6703
|
+
if (this.#stopping) return;
|
|
6704
|
+
const { table } = group;
|
|
6705
|
+
const names = [...group.names];
|
|
6706
|
+
while (names.length) {
|
|
6707
|
+
if (this.#stopping) return;
|
|
6708
|
+
const chunk = names.splice(0, 100);
|
|
6709
|
+
let batches = 0;
|
|
6710
|
+
let resolved = 0;
|
|
6711
|
+
do {
|
|
6712
|
+
if (this.#stopping) return;
|
|
6713
|
+
resolved = this.#config.noMultiMutationCte ? await this.#manager.resolveFlowJobsDistributed(table, chunk) : await this.#resolveStandard(table, chunk);
|
|
6714
|
+
if (resolved > 0) this.emit(events$2.flow, {
|
|
6715
|
+
table,
|
|
6716
|
+
resolved
|
|
6717
|
+
});
|
|
6718
|
+
} while (resolved >= 1e3 && ++batches < MAX_BATCHES_PER_PASS && !this.#stopping);
|
|
6719
|
+
}
|
|
6720
|
+
}
|
|
6721
|
+
}
|
|
6722
|
+
async #resolveStandard(table, names) {
|
|
6723
|
+
const query = resolveFlowJobs(this.#config.schema, table, names);
|
|
6724
|
+
const { rows } = await this.#db.executeSql(query.text, query.values);
|
|
6725
|
+
return Number(rows[0]?.resolved ?? 0);
|
|
6726
|
+
}
|
|
6727
|
+
};
|
|
6728
|
+
//#endregion
|
|
6373
6729
|
//#region ../../src/notifier.ts
|
|
6374
6730
|
var events$1 = {
|
|
6375
6731
|
error: "error",
|
|
@@ -6450,7 +6806,7 @@ var Db = class extends EventEmitter {
|
|
|
6450
6806
|
constructor(config) {
|
|
6451
6807
|
super();
|
|
6452
6808
|
config.application_name = config.application_name || "pgboss";
|
|
6453
|
-
config.connectionTimeoutMillis
|
|
6809
|
+
config.connectionTimeoutMillis ??= 1e4;
|
|
6454
6810
|
this.config = config;
|
|
6455
6811
|
this._pgbdb = true;
|
|
6456
6812
|
this.opened = false;
|
|
@@ -6551,7 +6907,8 @@ var events = Object.freeze({
|
|
|
6551
6907
|
warning: "warning",
|
|
6552
6908
|
wip: "wip",
|
|
6553
6909
|
stopped: "stopped",
|
|
6554
|
-
bam: "bam"
|
|
6910
|
+
bam: "bam",
|
|
6911
|
+
flow: "flow"
|
|
6555
6912
|
});
|
|
6556
6913
|
var PgBoss = class extends EventEmitter {
|
|
6557
6914
|
#stoppingOn;
|
|
@@ -6565,6 +6922,7 @@ var PgBoss = class extends EventEmitter {
|
|
|
6565
6922
|
#manager;
|
|
6566
6923
|
#timekeeper;
|
|
6567
6924
|
#bam;
|
|
6925
|
+
#navigator;
|
|
6568
6926
|
#notifier;
|
|
6569
6927
|
constructor(value) {
|
|
6570
6928
|
super();
|
|
@@ -6581,18 +6939,21 @@ var PgBoss = class extends EventEmitter {
|
|
|
6581
6939
|
const timekeeper = new Timekeeper(db, manager, config);
|
|
6582
6940
|
manager.timekeeper = timekeeper;
|
|
6583
6941
|
const bam = new Bam(db, config);
|
|
6942
|
+
const navigator = new Navigator(db, manager, config);
|
|
6584
6943
|
const notifier = new Notifier(db, manager, config);
|
|
6585
6944
|
manager.notifier = notifier;
|
|
6586
6945
|
this.#promoteEvents(manager);
|
|
6587
6946
|
this.#promoteEvents(boss);
|
|
6588
6947
|
this.#promoteEvents(timekeeper);
|
|
6589
6948
|
this.#promoteEvents(bam);
|
|
6949
|
+
this.#promoteEvents(navigator);
|
|
6590
6950
|
this.#promoteEvents(notifier);
|
|
6591
6951
|
this.#boss = boss;
|
|
6592
6952
|
this.#contractor = contractor;
|
|
6593
6953
|
this.#manager = manager;
|
|
6594
6954
|
this.#timekeeper = timekeeper;
|
|
6595
6955
|
this.#bam = bam;
|
|
6956
|
+
this.#navigator = navigator;
|
|
6596
6957
|
this.#notifier = notifier;
|
|
6597
6958
|
}
|
|
6598
6959
|
#promoteEvents(emitter) {
|
|
@@ -6608,7 +6969,10 @@ var PgBoss = class extends EventEmitter {
|
|
|
6608
6969
|
else await this.#contractor.check();
|
|
6609
6970
|
await this.#manager.start();
|
|
6610
6971
|
if (this.#config.useListenNotify) await this.#notifier.start();
|
|
6611
|
-
if (this.#config.supervise)
|
|
6972
|
+
if (this.#config.supervise) {
|
|
6973
|
+
await this.#boss.start();
|
|
6974
|
+
await this.#navigator.start();
|
|
6975
|
+
}
|
|
6612
6976
|
if (this.#config.schedule) await this.#timekeeper.start();
|
|
6613
6977
|
if (this.#config.migrate) await this.#bam.start();
|
|
6614
6978
|
} catch (err) {
|
|
@@ -6641,6 +7005,7 @@ var PgBoss = class extends EventEmitter {
|
|
|
6641
7005
|
await this.#manager.stop();
|
|
6642
7006
|
await this.#timekeeper.stop();
|
|
6643
7007
|
await this.#boss.stop();
|
|
7008
|
+
await this.#navigator.stop();
|
|
6644
7009
|
await this.#bam.stop();
|
|
6645
7010
|
const shutdown = async () => {
|
|
6646
7011
|
await this.#manager.failWip();
|
|
@@ -6708,6 +7073,9 @@ var PgBoss = class extends EventEmitter {
|
|
|
6708
7073
|
deleteJob(name, id, options) {
|
|
6709
7074
|
return this.#manager.deleteJob(name, id, options);
|
|
6710
7075
|
}
|
|
7076
|
+
redrive(name, options) {
|
|
7077
|
+
return this.#manager.redrive(name, options);
|
|
7078
|
+
}
|
|
6711
7079
|
deleteQueuedJobs(name) {
|
|
6712
7080
|
return this.#manager.deleteQueuedJobs(name);
|
|
6713
7081
|
}
|
|
@@ -6754,7 +7122,7 @@ var PgBoss = class extends EventEmitter {
|
|
|
6754
7122
|
return this.#manager.deleteQueue(name);
|
|
6755
7123
|
}
|
|
6756
7124
|
getQueues(names) {
|
|
6757
|
-
return this.#manager.getQueues();
|
|
7125
|
+
return this.#manager.getQueues(names);
|
|
6758
7126
|
}
|
|
6759
7127
|
getQueue(name) {
|
|
6760
7128
|
return this.#manager.getQueue(name);
|
|
@@ -6768,12 +7136,18 @@ var PgBoss = class extends EventEmitter {
|
|
|
6768
7136
|
isBamWorking() {
|
|
6769
7137
|
return this.#bam.working;
|
|
6770
7138
|
}
|
|
7139
|
+
isResolvingFlow() {
|
|
7140
|
+
return this.#navigator.working;
|
|
7141
|
+
}
|
|
6771
7142
|
isCheckingSkew() {
|
|
6772
7143
|
return this.#timekeeper.checkingSkew;
|
|
6773
7144
|
}
|
|
6774
7145
|
supervise(name) {
|
|
6775
7146
|
return this.#boss.supervise(name);
|
|
6776
7147
|
}
|
|
7148
|
+
resolveFlow() {
|
|
7149
|
+
return this.#navigator.resolveNow();
|
|
7150
|
+
}
|
|
6777
7151
|
getWipData(options) {
|
|
6778
7152
|
return this.#manager.getWipData(options);
|
|
6779
7153
|
}
|
|
@@ -10239,6 +10613,37 @@ var queues_$name_jobs_$jobId_default = UNSAFE_withComponentProps(function JobDet
|
|
|
10239
10613
|
})] })
|
|
10240
10614
|
]
|
|
10241
10615
|
}),
|
|
10616
|
+
(job.sourceName || job.sourceId) && /* @__PURE__ */ jsxs("div", {
|
|
10617
|
+
className: "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-x-6 gap-y-4",
|
|
10618
|
+
children: [
|
|
10619
|
+
job.sourceName && /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("dt", {
|
|
10620
|
+
className: "pgb-eyebrow",
|
|
10621
|
+
children: "Source Queue"
|
|
10622
|
+
}), /* @__PURE__ */ jsx("dd", {
|
|
10623
|
+
className: "mt-1 text-sm text-[var(--text-primary)]",
|
|
10624
|
+
children: /* @__PURE__ */ jsx(DbLink, {
|
|
10625
|
+
to: `/queues/${job.sourceName}`,
|
|
10626
|
+
className: "font-mono text-xs text-primary-600 hover:text-primary-700 dark:text-primary-400 dark:hover:text-primary-300",
|
|
10627
|
+
children: job.sourceName
|
|
10628
|
+
})
|
|
10629
|
+
})] }),
|
|
10630
|
+
job.sourceId && /* @__PURE__ */ jsx(ConfigItem, {
|
|
10631
|
+
label: "Source Job ID",
|
|
10632
|
+
value: job.sourceId,
|
|
10633
|
+
mono: true
|
|
10634
|
+
}),
|
|
10635
|
+
job.sourceRetryCount !== null && job.sourceRetryCount !== void 0 && /* @__PURE__ */ jsx(ConfigItem, {
|
|
10636
|
+
label: "Source Retry Count",
|
|
10637
|
+
value: job.sourceRetryCount,
|
|
10638
|
+
mono: true
|
|
10639
|
+
}),
|
|
10640
|
+
job.sourceCreatedOn && /* @__PURE__ */ jsx(ConfigItem, {
|
|
10641
|
+
label: "Source Created",
|
|
10642
|
+
value: formatDate(new Date(job.sourceCreatedOn)),
|
|
10643
|
+
mono: true
|
|
10644
|
+
})
|
|
10645
|
+
]
|
|
10646
|
+
}),
|
|
10242
10647
|
/* @__PURE__ */ jsxs("div", {
|
|
10243
10648
|
className: "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-5 gap-x-6 gap-y-4",
|
|
10244
10649
|
children: [
|
|
@@ -11708,7 +12113,7 @@ var server_manifest_default = {
|
|
|
11708
12113
|
"hasClientMiddleware": false,
|
|
11709
12114
|
"hasDefaultExport": true,
|
|
11710
12115
|
"hasErrorBoundary": true,
|
|
11711
|
-
"module": "/assets/queues._name.jobs._jobId-
|
|
12116
|
+
"module": "/assets/queues._name.jobs._jobId-DzHZmfcB.js",
|
|
11712
12117
|
"imports": [
|
|
11713
12118
|
"/assets/jsx-runtime-RQyiN6Nr.js",
|
|
11714
12119
|
"/assets/db-link-BajQ1v8I.js",
|
|
@@ -11902,8 +12307,8 @@ var server_manifest_default = {
|
|
|
11902
12307
|
"hydrateFallbackModule": void 0
|
|
11903
12308
|
}
|
|
11904
12309
|
},
|
|
11905
|
-
"url": "/assets/manifest-
|
|
11906
|
-
"version": "
|
|
12310
|
+
"url": "/assets/manifest-3e8f868c.js",
|
|
12311
|
+
"version": "3e8f868c",
|
|
11907
12312
|
"sri": void 0
|
|
11908
12313
|
};
|
|
11909
12314
|
//#endregion
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pg-boss/dashboard",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0",
|
|
4
4
|
"description": "Web dashboard for monitoring and managing pg-boss job queues",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pg-boss",
|
|
@@ -53,7 +53,7 @@
|
|
|
53
53
|
"isbot": "^5.1.44",
|
|
54
54
|
"lucide-react": "^1.21.0",
|
|
55
55
|
"pg": "^8.22.0",
|
|
56
|
-
"pg-boss": "^12.
|
|
56
|
+
"pg-boss": "^12.23.0",
|
|
57
57
|
"react": "^19.2.7",
|
|
58
58
|
"react-dom": "^19.2.7",
|
|
59
59
|
"react-router": "^8.0.1",
|