feat: manual triggers and give clients a hook into step run events (#141)

* feat: pubsub for clients, more qol stuff

* fix: generate sqlc files

* chore: linting and comments
This commit is contained in:
abelanger5
2024-02-02 09:52:34 -08:00
committed by GitHub
parent aed11c3958
commit 82d7995343
52 changed files with 2060 additions and 429 deletions
+38
View File
@@ -9,6 +9,8 @@ service Dispatcher {
rpc Listen(WorkerListenRequest) returns (stream AssignedAction) {}
rpc SubscribeToWorkflowEvents(SubscribeToWorkflowEventsRequest) returns (stream WorkflowEvent) {}
rpc SendStepActionEvent(StepActionEvent) returns (ActionEventResponse) {}
rpc SendGroupKeyActionEvent(GroupKeyActionEvent) returns (ActionEventResponse) {}
@@ -167,3 +169,39 @@ message ActionEventResponse {
// the id of the worker
string workerId = 2;
}
message SubscribeToWorkflowEventsRequest {
// the id of the workflow run
string workflowRunId = 1;
}
enum ResourceType {
RESOURCE_TYPE_UNKNOWN = 0;
RESOURCE_TYPE_STEP_RUN = 1;
RESOURCE_TYPE_WORKFLOW_RUN = 2;
}
enum ResourceEventType {
RESOURCE_EVENT_TYPE_UNKNOWN = 0;
RESOURCE_EVENT_TYPE_STARTED = 1;
RESOURCE_EVENT_TYPE_COMPLETED = 2;
RESOURCE_EVENT_TYPE_FAILED = 3;
RESOURCE_EVENT_TYPE_CANCELLED = 4;
RESOURCE_EVENT_TYPE_TIMED_OUT = 5;
}
message WorkflowEvent {
// the id of the workflow run
string workflowRunId = 1;
ResourceType resourceType = 2;
ResourceEventType eventType = 3;
string resourceId = 4;
google.protobuf.Timestamp eventTimestamp = 5;
// the event payload
string eventPayload = 6;
}
+12 -1
View File
@@ -10,10 +10,10 @@ service WorkflowService {
rpc ListWorkflows(ListWorkflowsRequest) returns (ListWorkflowsResponse);
rpc PutWorkflow(PutWorkflowRequest) returns (WorkflowVersion);
rpc ScheduleWorkflow(ScheduleWorkflowRequest) returns (WorkflowVersion);
rpc TriggerWorkflow(TriggerWorkflowRequest) returns (TriggerWorkflowResponse);
rpc GetWorkflowByName(GetWorkflowByNameRequest) returns (Workflow);
rpc ListWorkflowsForEvent(ListWorkflowsForEventRequest) returns (ListWorkflowsResponse);
rpc DeleteWorkflow(DeleteWorkflowRequest) returns (Workflow);
}
message PutWorkflowRequest {
@@ -161,4 +161,15 @@ message DeleteWorkflowRequest {
message GetWorkflowByNameRequest {
string name = 1;
}
message TriggerWorkflowRequest {
string name = 1;
// (optional) the input data for the workflow
string input = 2;
}
message TriggerWorkflowResponse {
string workflow_run_id = 1;
}
+74
View File
@@ -0,0 +1,74 @@
package main
import (
"fmt"
"time"
"github.com/joho/godotenv"
"github.com/hatchet-dev/hatchet/pkg/client"
"github.com/hatchet-dev/hatchet/pkg/cmdutils"
)
type userCreateEvent struct {
Username string `json:"username"`
UserID string `json:"user_id"`
Data map[string]string `json:"data"`
}
type stepOutput struct {
Message string `json:"message"`
}
func main() {
err := godotenv.Load()
if err != nil {
panic(err)
}
events := make(chan string, 50)
if err := run(cmdutils.InterruptChan(), events); err != nil {
panic(err)
}
}
func run(ch <-chan interface{}, events chan<- string) error {
c, err := client.New()
if err != nil {
return fmt.Errorf("error creating client: %w", err)
}
time.Sleep(1 * time.Second)
// trigger workflow
workflowRunId, err := c.Admin().RunWorkflow(
"post-user-update",
&userCreateEvent{
Username: "echo-test",
UserID: "1234",
Data: map[string]string{
"test": "test",
},
},
)
if err != nil {
return fmt.Errorf("error running workflow: %w", err)
}
fmt.Println("workflow run id:", workflowRunId)
interruptCtx, cancel := cmdutils.InterruptContextFromChan(ch)
defer cancel()
err = c.Run().On(interruptCtx, workflowRunId, func(event *client.StepRunEvent) error {
if event.Type == client.StepRunEventTypeCompleted {
fmt.Println(string(event.Payload))
}
return nil
})
return err
}
+136
View File
@@ -0,0 +1,136 @@
package main
import (
"fmt"
"time"
"github.com/joho/godotenv"
"github.com/hatchet-dev/hatchet/pkg/client"
"github.com/hatchet-dev/hatchet/pkg/cmdutils"
"github.com/hatchet-dev/hatchet/pkg/worker"
)
type userCreateEvent struct {
Username string `json:"username"`
UserID string `json:"user_id"`
Data map[string]string `json:"data"`
}
type stepOutput struct {
Message string `json:"message"`
}
func main() {
err := godotenv.Load()
if err != nil {
panic(err)
}
events := make(chan string, 50)
if err := run(cmdutils.InterruptChan(), events); err != nil {
panic(err)
}
}
func run(ch <-chan interface{}, events chan<- string) error {
c, err := client.New()
if err != nil {
return fmt.Errorf("error creating client: %w", err)
}
// Create a worker. This automatically reads in a TemporalClient from .env and workflow files from the .hatchet
// directory, but this can be customized with the `worker.WithTemporalClient` and `worker.WithWorkflowFiles` options.
w, err := worker.NewWorker(
worker.WithClient(
c,
),
)
if err != nil {
return fmt.Errorf("error creating worker: %w", err)
}
testSvc := w.NewService("test")
err = testSvc.On(
worker.Events("user:create:simple"),
&worker.WorkflowJob{
Name: "post-user-update",
Description: "This runs after an update to the user model.",
Steps: []*worker.WorkflowStep{
worker.Fn(func(ctx worker.HatchetContext) (result *stepOutput, err error) {
input := &userCreateEvent{}
ctx.WorkflowInput(input)
time.Sleep(1 * time.Second)
return &stepOutput{
Message: "Step 1 got username: " + input.Username,
}, nil
},
).SetName("step-one"),
worker.Fn(func(ctx worker.HatchetContext) (result *stepOutput, err error) {
input := &userCreateEvent{}
ctx.WorkflowInput(input)
time.Sleep(2 * time.Second)
return &stepOutput{
Message: "Step 2 got username: " + input.Username,
}, nil
}).SetName("step-two"),
worker.Fn(func(ctx worker.HatchetContext) (result *stepOutput, err error) {
step1Out := &stepOutput{}
ctx.StepOutput("step-one", step1Out)
step2Out := &stepOutput{}
ctx.StepOutput("step-two", step2Out)
time.Sleep(3 * time.Second)
return &stepOutput{
Message: "Step 3: has parents 1 and 2:" + step1Out.Message + ", " + step2Out.Message,
}, nil
}).SetName("step-three").AddParents("step-one", "step-two"),
worker.Fn(func(ctx worker.HatchetContext) (result *stepOutput, err error) {
step1Out := &stepOutput{}
ctx.StepOutput("step-one", step1Out)
step3Out := &stepOutput{}
ctx.StepOutput("step-three", step3Out)
time.Sleep(4 * time.Second)
return &stepOutput{
Message: "Step 4: has parents 1 and 3" + step1Out.Message + ", " + step3Out.Message,
}, nil
}).SetName("step-four").AddParents("step-one", "step-three"),
worker.Fn(func(ctx worker.HatchetContext) (result *stepOutput, err error) {
step4Out := &stepOutput{}
ctx.StepOutput("step-four", step4Out)
time.Sleep(5 * time.Second)
return &stepOutput{
Message: "Step 5: has parent 4" + step4Out.Message,
}, nil
}).SetName("step-five").AddParents("step-four"),
},
},
)
if err != nil {
return fmt.Errorf("error registering workflow: %w", err)
}
interruptCtx, cancel := cmdutils.InterruptContextFromChan(ch)
defer cancel()
err = w.Start(interruptCtx)
if err != nil {
panic(err)
}
return nil
}
+3
View File
@@ -19,6 +19,7 @@
"@heroicons/react": "^2.0.18",
"@hookform/resolvers": "^3.3.2",
"@lukemorales/query-key-factory": "^1.3.2",
"@monaco-editor/react": "^4.6.0",
"@radix-ui/react-accordion": "^1.1.2",
"@radix-ui/react-avatar": "^1.0.4",
"@radix-ui/react-checkbox": "^1.0.4",
@@ -32,6 +33,7 @@
"@radix-ui/react-select": "^2.0.0",
"@radix-ui/react-separator": "^1.0.3",
"@radix-ui/react-slot": "^1.0.2",
"@radix-ui/react-tabs": "^1.0.4",
"@radix-ui/react-toast": "^1.1.5",
"@tanstack/react-query": "^5.12.1",
"@tanstack/react-table": "^8.10.7",
@@ -54,6 +56,7 @@
"cronstrue": "^2.47.0",
"dagre": "^0.8.5",
"jotai": "^2.6.0",
"monaco-themes": "^0.4.4",
"prism-react-renderer": "^2.3.0",
"qs": "^6.11.2",
"react": "^18.2.0",
+77
View File
@@ -14,6 +14,9 @@ dependencies:
'@lukemorales/query-key-factory':
specifier: ^1.3.2
version: 1.3.2(@tanstack/query-core@5.12.1)(@tanstack/react-query@5.12.1)
'@monaco-editor/react':
specifier: ^4.6.0
version: 4.6.0(monaco-editor@0.45.0)(react-dom@18.2.0)(react@18.2.0)
'@radix-ui/react-accordion':
specifier: ^1.1.2
version: 1.1.2(@types/react-dom@18.2.17)(@types/react@18.2.39)(react-dom@18.2.0)(react@18.2.0)
@@ -53,6 +56,9 @@ dependencies:
'@radix-ui/react-slot':
specifier: ^1.0.2
version: 1.0.2(@types/react@18.2.39)(react@18.2.0)
'@radix-ui/react-tabs':
specifier: ^1.0.4
version: 1.0.4(@types/react-dom@18.2.17)(@types/react@18.2.39)(react-dom@18.2.0)(react@18.2.0)
'@radix-ui/react-toast':
specifier: ^1.1.5
version: 1.1.5(@types/react-dom@18.2.17)(@types/react@18.2.39)(react-dom@18.2.0)(react@18.2.0)
@@ -119,6 +125,9 @@ dependencies:
jotai:
specifier: ^2.6.0
version: 2.6.0(@types/react@18.2.39)(react@18.2.0)
monaco-themes:
specifier: ^0.4.4
version: 0.4.4
prism-react-renderer:
specifier: ^2.3.0
version: 2.3.0(react@18.2.0)
@@ -813,6 +822,28 @@ packages:
'@tanstack/react-query': 5.12.1(react@18.2.0)
dev: false
/@monaco-editor/loader@1.4.0(monaco-editor@0.45.0):
resolution: {integrity: sha512-00ioBig0x642hytVspPl7DbQyaSWRaolYie/UFNjoTdvoKPzo6xrXLhTk9ixgIKcLH5b5vDOjVNiGyY+uDCUlg==}
peerDependencies:
monaco-editor: '>= 0.21.0 < 1'
dependencies:
monaco-editor: 0.45.0
state-local: 1.0.7
dev: false
/@monaco-editor/react@4.6.0(monaco-editor@0.45.0)(react-dom@18.2.0)(react@18.2.0):
resolution: {integrity: sha512-RFkU9/i7cN2bsq/iTkurMWOEErmYcY6JiQI3Jn+WeR/FGISH8JbHERjpS9oRuSOPvDMJI0Z8nJeKkbOs9sBYQw==}
peerDependencies:
monaco-editor: '>= 0.25.0 < 1'
react: ^16.8.0 || ^17.0.0 || ^18.0.0
react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0
dependencies:
'@monaco-editor/loader': 1.4.0(monaco-editor@0.45.0)
monaco-editor: 0.45.0
react: 18.2.0
react-dom: 18.2.0(react@18.2.0)
dev: false
/@nodelib/fs.scandir@2.1.5:
resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
engines: {node: '>= 8'}
@@ -1697,6 +1728,34 @@ packages:
react: 18.2.0
dev: false
/@radix-ui/react-tabs@1.0.4(@types/react-dom@18.2.17)(@types/react@18.2.39)(react-dom@18.2.0)(react@18.2.0):
resolution: {integrity: sha512-egZfYY/+wRNCflXNHx+dePvnz9FbmssDTJBtgRfDY7e8SE5oIo3Py2eCB1ckAbh1Q7cQ/6yJZThJ++sgbxibog==}
peerDependencies:
'@types/react': '*'
'@types/react-dom': '*'
react: ^16.8 || ^17.0 || ^18.0
react-dom: ^16.8 || ^17.0 || ^18.0
peerDependenciesMeta:
'@types/react':
optional: true
'@types/react-dom':
optional: true
dependencies:
'@babel/runtime': 7.23.5
'@radix-ui/primitive': 1.0.1
'@radix-ui/react-context': 1.0.1(@types/react@18.2.39)(react@18.2.0)
'@radix-ui/react-direction': 1.0.1(@types/react@18.2.39)(react@18.2.0)
'@radix-ui/react-id': 1.0.1(@types/react@18.2.39)(react@18.2.0)
'@radix-ui/react-presence': 1.0.1(@types/react-dom@18.2.17)(@types/react@18.2.39)(react-dom@18.2.0)(react@18.2.0)
'@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.17)(@types/react@18.2.39)(react-dom@18.2.0)(react@18.2.0)
'@radix-ui/react-roving-focus': 1.0.4(@types/react-dom@18.2.17)(@types/react@18.2.39)(react-dom@18.2.0)(react@18.2.0)
'@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.2.39)(react@18.2.0)
'@types/react': 18.2.39
'@types/react-dom': 18.2.17
react: 18.2.0
react-dom: 18.2.0(react@18.2.0)
dev: false
/@radix-ui/react-toast@1.1.5(@types/react-dom@18.2.17)(@types/react@18.2.39)(react-dom@18.2.0)(react@18.2.0):
resolution: {integrity: sha512-fRLn227WHIBRSzuRzGJ8W+5YALxofH23y0MlPLddaIpLpCDqdE0NZlS2NRQDRiptfxDeeCjgFIpexB1/zkxDlw==}
peerDependencies:
@@ -3938,6 +3997,10 @@ packages:
resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==}
dev: true
/fast-plist@0.1.3:
resolution: {integrity: sha512-d9cEfo/WcOezgPLAC/8t8wGb6YOD6JTCPMw2QcG2nAdFmyY+9rTUizCTaGjIZAloWENTEUMAPpkUAIJJJ0i96A==}
dev: false
/fastq@1.15.0:
resolution: {integrity: sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==}
dependencies:
@@ -4701,6 +4764,16 @@ packages:
resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==}
dev: true
/monaco-editor@0.45.0:
resolution: {integrity: sha512-mjv1G1ZzfEE3k9HZN0dQ2olMdwIfaeAAjFiwNprLfYNRSz7ctv9XuCT7gPtBGrMUeV1/iZzYKj17Khu1hxoHOA==}
dev: false
/monaco-themes@0.4.4:
resolution: {integrity: sha512-Hbb9pvRrpSi0rZezcB/IOdQnpx10o55Lx4zFdRAAVpFMa1HP7FgaqEZdKffb4ovd90fETCixeFO9JPYFMAq+TQ==}
dependencies:
fast-plist: 0.1.3
dev: false
/ms@2.1.2:
resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==}
dev: true
@@ -5455,6 +5528,10 @@ packages:
resolution: {integrity: sha512-q/JSVd1Lptzhf5bkYm4ob4iWPjx0KiRe3sRFBNrVqbJkFaBm5vbbowy1mymoPNLRa52+oadOhJ+K49wsSeSjTA==}
dev: false
/state-local@1.0.7:
resolution: {integrity: sha512-HTEHMNieakEnoe33shBYcZ7NX83ACUjCu8c40iOGEZsngj9zRnkqS9j1pqQPXwobB0ZcVTk27REb7COQ0UR59w==}
dev: false
/string.prototype.matchall@4.0.10:
resolution: {integrity: sha512-rGXbGmOEosIQi6Qva94HUjgPs9vKW+dkG7Y8Q5O2OYkWL6wFaTRZO8zM4mhP94uX55wgyrXzfS2aGtGzUL7EJQ==}
dependencies:
@@ -0,0 +1,142 @@
import CopyToClipboard from './copy-to-clipboard';
import { cn } from '@/lib/utils';
import Editor, { Monaco } from '@monaco-editor/react';
import 'monaco-themes/themes/Pastels on Dark.json';
export function CodeEditor({
code,
setCode,
language,
className,
height,
width,
copy,
wrapLines = true,
}: {
code: string;
setCode?: (code: string) => void;
language: string;
className?: string;
height?: string;
width?: string;
copy?: boolean;
wrapLines?: boolean;
}) {
const setEditorTheme = (monaco: Monaco) => {
monaco.editor.defineTheme('pastels-on-dark', {
base: 'vs-dark',
inherit: true,
rules: [
{
background: '0D0D0D',
token: '',
},
{
foreground: '473c45',
token: 'comment',
},
{
foreground: 'c0c5ce',
token: 'string',
},
{
foreground: 'a8885a',
token: 'constant',
},
{
foreground: '4FB4D7',
token: 'variable.parameter',
},
{
foreground: '596380',
token: 'variable.other',
},
{
foreground: '728059',
token: 'keyword - keyword.operator',
},
{
foreground: '728059',
token: 'keyword.operator.logical',
},
{
foreground: '9ebf60',
token: 'storage',
},
{
foreground: '6078bf',
token: 'entity',
},
{
fontStyle: 'italic',
token: 'entity.other.inherited-class',
},
{
foreground: '8a4b66',
token: 'support',
},
{
foreground: '893062',
token: 'support.type.exception',
},
{
background: '5f0047',
token: 'invalid',
},
{
background: '371d28',
token: 'meta.function.section',
},
],
colors: {
'editor.foreground': '#1B283B',
'editor.background': '#1e293b',
'editor.selectionBackground': '#40002F',
'editor.lineHighlightBackground': '#00000012',
'editorCursor.foreground': '#7F005D',
'editorWhitespace.foreground': '#BFBFBF',
},
});
monaco.editor.setTheme('pastels-on-dark');
};
return (
<div
className={cn(
className,
'w-full h-fit relative rounded-lg overflow-hidden',
)}
>
<Editor
beforeMount={setEditorTheme}
language={language}
value={code}
width={width || '100%'}
height={height || '400px'}
theme="pastels-on-dark"
options={{
minimap: { enabled: false },
wordWrap: wrapLines ? 'on' : 'off',
lineNumbers: 'off',
theme: 'pastels-on-dark',
autoDetectHighContrast: true,
readOnly: !setCode,
scrollbar: { vertical: 'hidden', horizontal: 'hidden' },
showFoldingControls: language == 'json' ? 'always' : 'never',
lineDecorationsWidth: 0,
overviewRulerBorder: false,
colorDecorators: false,
hideCursorInOverviewRuler: true,
contextmenu: false,
}}
/>
{copy && (
<CopyToClipboard
className="absolute top-1 right-1"
text={code.trim()}
/>
)}
</div>
);
}
@@ -13,7 +13,7 @@ SyntaxHighlighter.registerLanguage('typescript', typescript);
SyntaxHighlighter.registerLanguage('yaml', yaml);
SyntaxHighlighter.registerLanguage('json', json);
export function Code({
export function CodeHighlighter({
code,
setCode,
language,
@@ -76,12 +76,7 @@ export function Code({
{code.trim()}
</SyntaxHighlighter>
</div>
{copy && (
<CopyToClipboard
className="absolute top-1 right-1"
text={code.trim()}
/>
)}
{copy && <CopyToClipboard text={code.trim()} withText />}
</div>
);
}
@@ -17,9 +17,11 @@ const CopyToClipboard: React.FC<Props> = ({ text, className, withText }) => {
<Button
className={cn(
className,
withText ? 'w-6 h-6 p-0 cursor-pointer' : 'cursor-pointer',
withText
? 'cursor-pointer flex flex-row gap-2 items-center mt-2'
: 'w-6 h-6 p-0 cursor-pointer',
)}
variant="ghost"
variant={withText ? 'default' : 'ghost'}
onClick={() => {
navigator.clipboard.writeText(text);
setSuccessCopy(true);
@@ -34,7 +36,7 @@ const CopyToClipboard: React.FC<Props> = ({ text, className, withText }) => {
) : (
<CopyIcon className="w-4 h-4" />
)}
{withText && (successCopy ? 'Copied' : 'Copy')}
{withText && (successCopy ? 'Copied' : 'Copy to clipboard')}
</Button>
);
};
+53
View File
@@ -0,0 +1,53 @@
import * as React from 'react';
import * as TabsPrimitive from '@radix-ui/react-tabs';
import { cn } from '@/lib/utils';
const Tabs = TabsPrimitive.Root;
const TabsList = React.forwardRef<
React.ElementRef<typeof TabsPrimitive.List>,
React.ComponentPropsWithoutRef<typeof TabsPrimitive.List>
>(({ className, ...props }, ref) => (
<TabsPrimitive.List
ref={ref}
className={cn(
'inline-flex h-9 items-center justify-center rounded-lg bg-muted p-1 text-muted-foreground',
className,
)}
{...props}
/>
));
TabsList.displayName = TabsPrimitive.List.displayName;
const TabsTrigger = React.forwardRef<
React.ElementRef<typeof TabsPrimitive.Trigger>,
React.ComponentPropsWithoutRef<typeof TabsPrimitive.Trigger>
>(({ className, ...props }, ref) => (
<TabsPrimitive.Trigger
ref={ref}
className={cn(
'inline-flex items-center justify-center whitespace-nowrap rounded-md px-3 py-1 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow',
className,
)}
{...props}
/>
));
TabsTrigger.displayName = TabsPrimitive.Trigger.displayName;
const TabsContent = React.forwardRef<
React.ElementRef<typeof TabsPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof TabsPrimitive.Content>
>(({ className, ...props }, ref) => (
<TabsPrimitive.Content
ref={ref}
className={cn(
'mt-2 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2',
className,
)}
{...props}
/>
));
TabsContent.displayName = TabsPrimitive.Content.displayName;
export { Tabs, TabsList, TabsTrigger, TabsContent };
+3 -3
View File
@@ -27,7 +27,7 @@ import {
DialogTitle,
} from '@/components/ui/dialog';
import { relativeDate } from '@/lib/utils';
import { Code } from '@/components/ui/code';
import { CodeEditor } from '@/components/ui/code-editor';
import { useOutletContext, useSearchParams } from 'react-router-dom';
import { Button } from '@/components/ui/button';
import {
@@ -338,10 +338,10 @@ function EventDataSection({ event }: { event: Event }) {
return (
<>
<Code
<CodeEditor
language="json"
className="my-4"
maxHeight="400px"
height="400px"
code={JSON.stringify(JSON.parse(eventData.data), null, 2)}
/>
</>
@@ -3,7 +3,6 @@ import {
DialogHeader,
DialogTitle,
} from '@/components/ui/dialog';
import { Code } from '@/components/ui/code';
import { Button } from '@/components/ui/button';
import { z } from 'zod';
import { useForm } from 'react-hook-form';
@@ -12,6 +11,7 @@ import { Label } from '@/components/ui/label';
import { Input } from '@/components/ui/input';
import { cn } from '@/lib/utils';
import { Spinner } from '@/components/ui/loading';
import { CodeHighlighter } from '@/components/ui/code-highlighter';
const schema = z.object({
name: z.string().min(1).max(255),
@@ -50,7 +50,7 @@ export function CreateTokenDialog({
This is the only time we will show you this token. Make sure to copy
it somewhere safe.
</p>
<Code
<CodeHighlighter
language="typescript"
className="text-sm"
wrapLines={false}
@@ -0,0 +1,33 @@
import { StepRun } from '@/lib/api';
import { CodeEditor } from '@/components/ui/code-editor';
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
export function StepInputOutputSection({ stepRun }: { stepRun: StepRun }) {
const input = stepRun.input || '{}';
const output = stepRun.output || '{}';
return (
<Tabs defaultValue="input" className="w-full">
<TabsList className="grid w-full grid-cols-2">
<TabsTrigger value="input">Input</TabsTrigger>
<TabsTrigger value="output">Output</TabsTrigger>
</TabsList>
<TabsContent value="input">
<CodeEditor
language="json"
className="my-4"
height="400px"
code={JSON.stringify(JSON.parse(input), null, 2)}
/>
</TabsContent>
<TabsContent value="output">
<CodeEditor
language="json"
className="my-4"
height="400px"
code={JSON.stringify(JSON.parse(output), null, 2)}
/>
</TabsContent>
</Tabs>
);
}
@@ -1,4 +1,3 @@
import { Code } from '@/components/ui/code';
import {
Dialog,
DialogContent,
@@ -7,9 +6,9 @@ import {
DialogTitle,
} from '@/components/ui/dialog';
import { StepRun, StepRunStatus } from '@/lib/api';
import { useEffect, useState } from 'react';
import { RunStatus } from '../../components/run-statuses';
import { getTiming } from './step-run-node';
import { StepInputOutputSection } from './step-run-input-output';
export function StepRunPlayground({
stepRun,
@@ -18,20 +17,6 @@ export function StepRunPlayground({
stepRun: StepRun | null;
setStepRun: (stepRun: StepRun | null) => void;
}) {
const originalInput = JSON.stringify(
JSON.parse(stepRun?.input || '{}'),
null,
2,
);
const output = JSON.stringify(JSON.parse(stepRun?.output || '{}'), null, 2);
const [stepInput, setStepInput] = useState(originalInput);
useEffect(() => {
setStepInput(JSON.stringify(JSON.parse(stepRun?.input || '{}'), null, 2));
}, [stepRun]);
return (
<Dialog
open={!!stepRun}
@@ -45,9 +30,7 @@ export function StepRunPlayground({
<DialogHeader>
<div className="flex flex-row justify-between items-center">
<DialogTitle>
{'Coding Assistant' ||
stepRun?.step?.readableId ||
stepRun?.metadata.id}
{stepRun?.step?.readableId || stepRun?.metadata.id}
</DialogTitle>
<RunStatus status={stepRun?.status || StepRunStatus.PENDING} />
</div>
@@ -73,25 +56,7 @@ export function StepRunPlayground({
Rerun Step
</Button> */}
</div>
{stepInput && (
<Code
language="json"
copy={true}
code={stepInput}
setCode={setStepInput}
wrapLines={false}
className="max-w-full"
/>
)}
<div className="font-bold">Output</div>
<Code
language="json"
code={output}
copy={true}
maxHeight="300px"
wrapLines={true}
className="max-w-full"
/>
{stepRun && <StepInputOutputSection stepRun={stepRun} />}
</DialogContent>
</Dialog>
);
@@ -45,10 +45,12 @@ const WorkflowRunVisualizer = ({
return (
stepRun.step.parents
?.map((parent) => {
invariant(stepRun.step, 'has step');
return {
id: `${parent}-${stepRun.metadata.id}`,
id: `${parent}-${stepRun.step.metadata.id}`,
source: parent,
target: stepRun.metadata.id,
target: stepRun.step.metadata.id,
animated: stepRun.status === StepRunStatus.RUNNING,
style: { stroke: '#fff' },
markerEnd: {
@@ -69,14 +71,16 @@ const WorkflowRunVisualizer = ({
invariant(jobRun.stepRuns, 'has stepRuns');
return jobRun.stepRuns.map((stepRun) => {
const hasChild = stepEdges.some(
(edge) => edge?.source === stepRun.metadata.id,
);
invariant(stepRun.step, 'has step');
const hasChild = stepEdges.some((edge) => {
invariant(stepRun.step, 'has step');
return edge?.source === stepRun.step.metadata.id;
});
const hasParent =
stepRun.step?.parents?.length && stepRun.step.parents.length > 0;
return {
id: stepRun.metadata.id,
id: stepRun.step.metadata.id,
selectable: false,
type: 'stepNode',
position: { x: 0, y: 0 }, // positioning gets set by dagre later
@@ -18,10 +18,11 @@ import { TableCell, TableRow } from '@/components/ui/table';
import { RunStatus } from '../components/run-statuses';
import { ColumnDef } from '@tanstack/react-table';
import { useState } from 'react';
import { Code } from '@/components/ui/code';
import { CodeEditor } from '@/components/ui/code-editor';
import { Loading } from '@/components/ui/loading.tsx';
import { TenantContextType } from '@/lib/outlet';
import WorkflowRunVisualizer from './components/workflow-run-visualizer';
import { StepInputOutputSection } from './components/step-run-input-output';
export default function ExpandedWorkflowRun() {
const [expandedStepRuns, setExpandedStepRuns] = useState<string[]>([]);
@@ -215,49 +216,12 @@ function getExpandedStepRunRow({
<TableCell colSpan={columns.length} className="px-8 py-4">
<StepStatusSection stepRun={stepRun} />
<StepConfigurationSection stepRun={stepRun} />
<StepInputSection stepRun={stepRun} />
<StepOutputSection stepRun={stepRun} />
<StepInputOutputSection stepRun={stepRun} />
</TableCell>
</TableRow>
);
}
function StepInputSection({ stepRun }: { stepRun: StepRun }) {
const input = stepRun.input || '{}';
return (
<>
<h3 className="font-semibold leading-tight text-foreground mb-4">
Input
</h3>
<Code
language="json"
className="my-4"
maxHeight="400px"
code={JSON.stringify(JSON.parse(input), null, 2)}
/>
</>
);
}
function StepOutputSection({ stepRun }: { stepRun: StepRun }) {
const output = stepRun.output || '{}';
return (
<>
<h3 className="font-semibold leading-tight text-foreground mb-4">
Output
</h3>
<Code
language="json"
className="my-4"
maxHeight="400px"
code={JSON.stringify(JSON.parse(output), null, 2)}
/>
</>
);
}
function StepStatusSection({ stepRun }: { stepRun: StepRun }) {
let statusText = 'Unknown';
@@ -350,10 +314,10 @@ function EventDataSection({ event }: { event: Event }) {
return (
<>
<Code
<CodeEditor
language="json"
className="my-4"
maxHeight="400px"
height="400px"
code={JSON.stringify(JSON.parse(eventData.data), null, 2)}
/>
</>
@@ -371,7 +335,7 @@ function TriggeringCronSection({ cron }: { cron: string }) {
Triggered by Cron
</h3>
<div className="text-sm text-muted-foreground">{prettyInterval}</div>
<Code language="typescript" className="my-4" code={cron} />
<CodeEditor language="typescript" className="my-4" code={cron} />
</>
);
}
+1
View File
@@ -12,6 +12,7 @@ const (
TriggeredByEvent TriggeredBy = "event"
TriggeredByCron TriggeredBy = "cron"
TriggeredBySchedule TriggeredBy = "schedule"
TriggeredByManual TriggeredBy = "manual"
)
type JobRunLookupData struct {
@@ -31,7 +31,7 @@ SET
WHERE
"id" = $10::uuid AND
"tenantId" = $11::uuid
RETURNING "GetGroupKeyRun".id, "GetGroupKeyRun"."createdAt", "GetGroupKeyRun"."updatedAt", "GetGroupKeyRun"."deletedAt", "GetGroupKeyRun"."tenantId", "GetGroupKeyRun"."workerId", "GetGroupKeyRun"."tickerId", "GetGroupKeyRun".status, "GetGroupKeyRun".input, "GetGroupKeyRun".output, "GetGroupKeyRun"."requeueAfter", "GetGroupKeyRun".error, "GetGroupKeyRun"."startedAt", "GetGroupKeyRun"."finishedAt", "GetGroupKeyRun"."timeoutAt", "GetGroupKeyRun"."cancelledAt", "GetGroupKeyRun"."cancelledReason", "GetGroupKeyRun"."cancelledError", "GetGroupKeyRun"."workflowRunId"
RETURNING "GetGroupKeyRun".id, "GetGroupKeyRun"."createdAt", "GetGroupKeyRun"."updatedAt", "GetGroupKeyRun"."deletedAt", "GetGroupKeyRun"."tenantId", "GetGroupKeyRun"."workflowRunId", "GetGroupKeyRun"."workerId", "GetGroupKeyRun"."tickerId", "GetGroupKeyRun".status, "GetGroupKeyRun".input, "GetGroupKeyRun".output, "GetGroupKeyRun"."requeueAfter", "GetGroupKeyRun".error, "GetGroupKeyRun"."startedAt", "GetGroupKeyRun"."finishedAt", "GetGroupKeyRun"."timeoutAt", "GetGroupKeyRun"."cancelledAt", "GetGroupKeyRun"."cancelledReason", "GetGroupKeyRun"."cancelledError"
`
type UpdateGetGroupKeyRunParams struct {
@@ -69,6 +69,7 @@ func (q *Queries) UpdateGetGroupKeyRun(ctx context.Context, db DBTX, arg UpdateG
&i.UpdatedAt,
&i.DeletedAt,
&i.TenantId,
&i.WorkflowRunId,
&i.WorkerId,
&i.TickerId,
&i.Status,
@@ -82,7 +83,6 @@ func (q *Queries) UpdateGetGroupKeyRun(ctx context.Context, db DBTX, arg UpdateG
&i.CancelledAt,
&i.CancelledReason,
&i.CancelledError,
&i.WorkflowRunId,
)
return &i, err
}
@@ -62,7 +62,7 @@ WHERE "id" = (
FROM "StepRun"
WHERE "id" = $1::uuid
) AND "tenantId" = $2::uuid
RETURNING "JobRun".id, "JobRun"."createdAt", "JobRun"."updatedAt", "JobRun"."deletedAt", "JobRun"."tenantId", "JobRun"."jobId", "JobRun"."tickerId", "JobRun".status, "JobRun".result, "JobRun"."startedAt", "JobRun"."finishedAt", "JobRun"."timeoutAt", "JobRun"."cancelledAt", "JobRun"."cancelledReason", "JobRun"."cancelledError", "JobRun"."workflowRunId"
RETURNING "JobRun".id, "JobRun"."createdAt", "JobRun"."updatedAt", "JobRun"."deletedAt", "JobRun"."tenantId", "JobRun"."workflowRunId", "JobRun"."jobId", "JobRun"."tickerId", "JobRun".status, "JobRun".result, "JobRun"."startedAt", "JobRun"."finishedAt", "JobRun"."timeoutAt", "JobRun"."cancelledAt", "JobRun"."cancelledReason", "JobRun"."cancelledError"
`
type ResolveJobRunStatusParams struct {
@@ -79,6 +79,7 @@ func (q *Queries) ResolveJobRunStatus(ctx context.Context, db DBTX, arg ResolveJ
&i.UpdatedAt,
&i.DeletedAt,
&i.TenantId,
&i.WorkflowRunId,
&i.JobId,
&i.TickerId,
&i.Status,
@@ -89,7 +90,6 @@ func (q *Queries) ResolveJobRunStatus(ctx context.Context, db DBTX, arg ResolveJ
&i.CancelledAt,
&i.CancelledReason,
&i.CancelledError,
&i.WorkflowRunId,
)
return &i, err
}
@@ -105,7 +105,7 @@ END
WHERE
"id" = $2::uuid AND
"tenantId" = $3::uuid
RETURNING "JobRun".id, "JobRun"."createdAt", "JobRun"."updatedAt", "JobRun"."deletedAt", "JobRun"."tenantId", "JobRun"."jobId", "JobRun"."tickerId", "JobRun".status, "JobRun".result, "JobRun"."startedAt", "JobRun"."finishedAt", "JobRun"."timeoutAt", "JobRun"."cancelledAt", "JobRun"."cancelledReason", "JobRun"."cancelledError", "JobRun"."workflowRunId"
RETURNING "JobRun".id, "JobRun"."createdAt", "JobRun"."updatedAt", "JobRun"."deletedAt", "JobRun"."tenantId", "JobRun"."workflowRunId", "JobRun"."jobId", "JobRun"."tickerId", "JobRun".status, "JobRun".result, "JobRun"."startedAt", "JobRun"."finishedAt", "JobRun"."timeoutAt", "JobRun"."cancelledAt", "JobRun"."cancelledReason", "JobRun"."cancelledError"
`
type UpdateJobRunParams struct {
@@ -123,6 +123,7 @@ func (q *Queries) UpdateJobRun(ctx context.Context, db DBTX, arg UpdateJobRunPar
&i.UpdatedAt,
&i.DeletedAt,
&i.TenantId,
&i.WorkflowRunId,
&i.JobId,
&i.TickerId,
&i.Status,
@@ -133,7 +134,6 @@ func (q *Queries) UpdateJobRun(ctx context.Context, db DBTX, arg UpdateJobRunPar
&i.CancelledAt,
&i.CancelledReason,
&i.CancelledError,
&i.WorkflowRunId,
)
return &i, err
}
+13 -12
View File
@@ -278,10 +278,10 @@ type WorkflowRunStatus string
const (
WorkflowRunStatusPENDING WorkflowRunStatus = "PENDING"
WorkflowRunStatusQUEUED WorkflowRunStatus = "QUEUED"
WorkflowRunStatusRUNNING WorkflowRunStatus = "RUNNING"
WorkflowRunStatusSUCCEEDED WorkflowRunStatus = "SUCCEEDED"
WorkflowRunStatusFAILED WorkflowRunStatus = "FAILED"
WorkflowRunStatusQUEUED WorkflowRunStatus = "QUEUED"
)
func (e *WorkflowRunStatus) Scan(src interface{}) error {
@@ -330,15 +330,15 @@ type APIToken struct {
}
type Action struct {
ID pgtype.UUID `json:"id"`
ActionId string `json:"actionId"`
Description pgtype.Text `json:"description"`
TenantId pgtype.UUID `json:"tenantId"`
ActionId string `json:"actionId"`
ID pgtype.UUID `json:"id"`
}
type ActionToWorker struct {
B pgtype.UUID `json:"B"`
A pgtype.UUID `json:"A"`
B pgtype.UUID `json:"B"`
}
type Dispatcher struct {
@@ -367,6 +367,7 @@ type GetGroupKeyRun struct {
UpdatedAt pgtype.Timestamp `json:"updatedAt"`
DeletedAt pgtype.Timestamp `json:"deletedAt"`
TenantId pgtype.UUID `json:"tenantId"`
WorkflowRunId pgtype.UUID `json:"workflowRunId"`
WorkerId pgtype.UUID `json:"workerId"`
TickerId pgtype.UUID `json:"tickerId"`
Status StepRunStatus `json:"status"`
@@ -380,7 +381,6 @@ type GetGroupKeyRun struct {
CancelledAt pgtype.Timestamp `json:"cancelledAt"`
CancelledReason pgtype.Text `json:"cancelledReason"`
CancelledError pgtype.Text `json:"cancelledError"`
WorkflowRunId pgtype.UUID `json:"workflowRunId"`
}
type Job struct {
@@ -401,6 +401,7 @@ type JobRun struct {
UpdatedAt pgtype.Timestamp `json:"updatedAt"`
DeletedAt pgtype.Timestamp `json:"deletedAt"`
TenantId pgtype.UUID `json:"tenantId"`
WorkflowRunId pgtype.UUID `json:"workflowRunId"`
JobId pgtype.UUID `json:"jobId"`
TickerId pgtype.UUID `json:"tickerId"`
Status JobRunStatus `json:"status"`
@@ -411,7 +412,6 @@ type JobRun struct {
CancelledAt pgtype.Timestamp `json:"cancelledAt"`
CancelledReason pgtype.Text `json:"cancelledReason"`
CancelledError pgtype.Text `json:"cancelledError"`
WorkflowRunId pgtype.UUID `json:"workflowRunId"`
}
type JobRunLookupData struct {
@@ -541,9 +541,9 @@ type UserOAuth struct {
UserId pgtype.UUID `json:"userId"`
Provider string `json:"provider"`
ProviderUserId string `json:"providerUserId"`
ExpiresAt pgtype.Timestamp `json:"expiresAt"`
AccessToken []byte `json:"accessToken"`
RefreshToken []byte `json:"refreshToken"`
ExpiresAt pgtype.Timestamp `json:"expiresAt"`
}
type UserPassword struct {
@@ -593,18 +593,18 @@ type WorkflowConcurrency struct {
}
type WorkflowRun struct {
ID pgtype.UUID `json:"id"`
CreatedAt pgtype.Timestamp `json:"createdAt"`
UpdatedAt pgtype.Timestamp `json:"updatedAt"`
DeletedAt pgtype.Timestamp `json:"deletedAt"`
DisplayName pgtype.Text `json:"displayName"`
TenantId pgtype.UUID `json:"tenantId"`
WorkflowVersionId pgtype.UUID `json:"workflowVersionId"`
ConcurrencyGroupId pgtype.Text `json:"concurrencyGroupId"`
Status WorkflowRunStatus `json:"status"`
Error pgtype.Text `json:"error"`
StartedAt pgtype.Timestamp `json:"startedAt"`
FinishedAt pgtype.Timestamp `json:"finishedAt"`
ConcurrencyGroupId pgtype.Text `json:"concurrencyGroupId"`
DisplayName pgtype.Text `json:"displayName"`
ID pgtype.UUID `json:"id"`
}
type WorkflowRunTriggeredBy struct {
@@ -613,11 +613,12 @@ type WorkflowRunTriggeredBy struct {
UpdatedAt pgtype.Timestamp `json:"updatedAt"`
DeletedAt pgtype.Timestamp `json:"deletedAt"`
TenantId pgtype.UUID `json:"tenantId"`
ParentId pgtype.UUID `json:"parentId"`
Input []byte `json:"input"`
EventId pgtype.UUID `json:"eventId"`
CronParentId pgtype.UUID `json:"cronParentId"`
CronSchedule pgtype.Text `json:"cronSchedule"`
ScheduledId pgtype.UUID `json:"scheduledId"`
ParentId pgtype.UUID `json:"parentId"`
}
type WorkflowTag struct {
@@ -668,8 +669,8 @@ type WorkflowVersion struct {
CreatedAt pgtype.Timestamp `json:"createdAt"`
UpdatedAt pgtype.Timestamp `json:"updatedAt"`
DeletedAt pgtype.Timestamp `json:"deletedAt"`
Checksum string `json:"checksum"`
Version pgtype.Text `json:"version"`
Order int16 `json:"order"`
WorkflowId pgtype.UUID `json:"workflowId"`
Checksum string `json:"checksum"`
}
+14 -13
View File
@@ -17,7 +17,7 @@ CREATE TYPE "TenantMemberRole" AS ENUM ('OWNER', 'ADMIN', 'MEMBER');
CREATE TYPE "WorkerStatus" AS ENUM ('ACTIVE', 'INACTIVE');
-- CreateEnum
CREATE TYPE "WorkflowRunStatus" AS ENUM ('PENDING', 'RUNNING', 'SUCCEEDED', 'FAILED', 'QUEUED');
CREATE TYPE "WorkflowRunStatus" AS ENUM ('PENDING', 'QUEUED', 'RUNNING', 'SUCCEEDED', 'FAILED');
-- CreateTable
CREATE TABLE "APIToken" (
@@ -34,10 +34,10 @@ CREATE TABLE "APIToken" (
-- CreateTable
CREATE TABLE "Action" (
"id" UUID NOT NULL,
"actionId" TEXT NOT NULL,
"description" TEXT,
"tenantId" UUID NOT NULL,
"actionId" TEXT NOT NULL,
"id" UUID NOT NULL,
CONSTRAINT "Action_pkey" PRIMARY KEY ("id")
);
@@ -75,6 +75,7 @@ CREATE TABLE "GetGroupKeyRun" (
"updatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"deletedAt" TIMESTAMP(3),
"tenantId" UUID NOT NULL,
"workflowRunId" UUID NOT NULL,
"workerId" UUID,
"tickerId" UUID,
"status" "StepRunStatus" NOT NULL DEFAULT 'PENDING',
@@ -88,7 +89,6 @@ CREATE TABLE "GetGroupKeyRun" (
"cancelledAt" TIMESTAMP(3),
"cancelledReason" TEXT,
"cancelledError" TEXT,
"workflowRunId" UUID NOT NULL,
CONSTRAINT "GetGroupKeyRun_pkey" PRIMARY KEY ("id")
);
@@ -115,6 +115,7 @@ CREATE TABLE "JobRun" (
"updatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"deletedAt" TIMESTAMP(3),
"tenantId" UUID NOT NULL,
"workflowRunId" UUID NOT NULL,
"jobId" UUID NOT NULL,
"tickerId" UUID,
"status" "JobRunStatus" NOT NULL DEFAULT 'PENDING',
@@ -125,7 +126,6 @@ CREATE TABLE "JobRun" (
"cancelledAt" TIMESTAMP(3),
"cancelledReason" TEXT,
"cancelledError" TEXT,
"workflowRunId" UUID NOT NULL,
CONSTRAINT "JobRun_pkey" PRIMARY KEY ("id")
);
@@ -270,9 +270,9 @@ CREATE TABLE "UserOAuth" (
"userId" UUID NOT NULL,
"provider" TEXT NOT NULL,
"providerUserId" TEXT NOT NULL,
"expiresAt" TIMESTAMP(3),
"accessToken" BYTEA NOT NULL,
"refreshToken" BYTEA,
"expiresAt" TIMESTAMP(3),
CONSTRAINT "UserOAuth_pkey" PRIMARY KEY ("id")
);
@@ -338,18 +338,18 @@ CREATE TABLE "WorkflowConcurrency" (
-- CreateTable
CREATE TABLE "WorkflowRun" (
"id" UUID NOT NULL,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"deletedAt" TIMESTAMP(3),
"displayName" TEXT,
"tenantId" UUID NOT NULL,
"workflowVersionId" UUID NOT NULL,
"concurrencyGroupId" TEXT,
"status" "WorkflowRunStatus" NOT NULL DEFAULT 'PENDING',
"error" TEXT,
"startedAt" TIMESTAMP(3),
"finishedAt" TIMESTAMP(3),
"concurrencyGroupId" TEXT,
"displayName" TEXT,
"id" UUID NOT NULL,
CONSTRAINT "WorkflowRun_pkey" PRIMARY KEY ("id")
);
@@ -361,11 +361,12 @@ CREATE TABLE "WorkflowRunTriggeredBy" (
"updatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"deletedAt" TIMESTAMP(3),
"tenantId" UUID NOT NULL,
"parentId" UUID NOT NULL,
"input" JSONB,
"eventId" UUID,
"cronParentId" UUID,
"cronSchedule" TEXT,
"scheduledId" UUID,
"parentId" UUID NOT NULL,
CONSTRAINT "WorkflowRunTriggeredBy_pkey" PRIMARY KEY ("id")
);
@@ -425,18 +426,18 @@ CREATE TABLE "WorkflowVersion" (
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"deletedAt" TIMESTAMP(3),
"checksum" TEXT NOT NULL,
"version" TEXT,
"order" SMALLSERIAL NOT NULL,
"workflowId" UUID NOT NULL,
"checksum" TEXT NOT NULL,
CONSTRAINT "WorkflowVersion_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "_ActionToWorker" (
"B" UUID NOT NULL,
"A" UUID NOT NULL
"A" UUID NOT NULL,
"B" UUID NOT NULL
);
-- CreateTable
@@ -112,7 +112,7 @@ INSERT INTO "GetGroupKeyRun" (
NULL,
NULL,
NULL
) RETURNING id, "createdAt", "updatedAt", "deletedAt", "tenantId", "workerId", "tickerId", status, input, output, "requeueAfter", error, "startedAt", "finishedAt", "timeoutAt", "cancelledAt", "cancelledReason", "cancelledError", "workflowRunId"
) RETURNING id, "createdAt", "updatedAt", "deletedAt", "tenantId", "workflowRunId", "workerId", "tickerId", status, input, output, "requeueAfter", error, "startedAt", "finishedAt", "timeoutAt", "cancelledAt", "cancelledReason", "cancelledError"
`
type CreateGetGroupKeyRunParams struct {
@@ -138,6 +138,7 @@ func (q *Queries) CreateGetGroupKeyRun(ctx context.Context, db DBTX, arg CreateG
&i.UpdatedAt,
&i.DeletedAt,
&i.TenantId,
&i.WorkflowRunId,
&i.WorkerId,
&i.TickerId,
&i.Status,
@@ -151,7 +152,6 @@ func (q *Queries) CreateGetGroupKeyRun(ctx context.Context, db DBTX, arg CreateG
&i.CancelledAt,
&i.CancelledReason,
&i.CancelledError,
&i.WorkflowRunId,
)
return &i, err
}
@@ -191,7 +191,7 @@ INSERT INTO "JobRun" (
NULL,
NULL,
NULL
) RETURNING id, "createdAt", "updatedAt", "deletedAt", "tenantId", "jobId", "tickerId", status, result, "startedAt", "finishedAt", "timeoutAt", "cancelledAt", "cancelledReason", "cancelledError", "workflowRunId"
) RETURNING id, "createdAt", "updatedAt", "deletedAt", "tenantId", "workflowRunId", "jobId", "tickerId", status, result, "startedAt", "finishedAt", "timeoutAt", "cancelledAt", "cancelledReason", "cancelledError"
`
type CreateJobRunParams struct {
@@ -215,6 +215,7 @@ func (q *Queries) CreateJobRun(ctx context.Context, db DBTX, arg CreateJobRunPar
&i.UpdatedAt,
&i.DeletedAt,
&i.TenantId,
&i.WorkflowRunId,
&i.JobId,
&i.TickerId,
&i.Status,
@@ -225,7 +226,6 @@ func (q *Queries) CreateJobRun(ctx context.Context, db DBTX, arg CreateJobRunPar
&i.CancelledAt,
&i.CancelledReason,
&i.CancelledError,
&i.WorkflowRunId,
)
return &i, err
}
@@ -402,7 +402,7 @@ INSERT INTO "WorkflowRun" (
NULL, -- assuming error is not set on creation
NULL, -- assuming startedAt is not set on creation
NULL -- assuming finishedAt is not set on creation
) RETURNING "createdAt", "updatedAt", "deletedAt", "tenantId", "workflowVersionId", status, error, "startedAt", "finishedAt", "concurrencyGroupId", "displayName", id
) RETURNING id, "createdAt", "updatedAt", "deletedAt", "displayName", "tenantId", "workflowVersionId", "concurrencyGroupId", status, error, "startedAt", "finishedAt"
`
type CreateWorkflowRunParams struct {
@@ -421,18 +421,18 @@ func (q *Queries) CreateWorkflowRun(ctx context.Context, db DBTX, arg CreateWork
)
var i WorkflowRun
err := row.Scan(
&i.ID,
&i.CreatedAt,
&i.UpdatedAt,
&i.DeletedAt,
&i.DisplayName,
&i.TenantId,
&i.WorkflowVersionId,
&i.ConcurrencyGroupId,
&i.Status,
&i.Error,
&i.StartedAt,
&i.FinishedAt,
&i.ConcurrencyGroupId,
&i.DisplayName,
&i.ID,
)
return &i, err
}
@@ -460,7 +460,7 @@ INSERT INTO "WorkflowRunTriggeredBy" (
$4::uuid, -- NULL if not provided
$5::text, -- NULL if not provided
$6::uuid -- NULL if not provided
) RETURNING id, "createdAt", "updatedAt", "deletedAt", "tenantId", "eventId", "cronParentId", "cronSchedule", "scheduledId", "parentId"
) RETURNING id, "createdAt", "updatedAt", "deletedAt", "tenantId", "parentId", input, "eventId", "cronParentId", "cronSchedule", "scheduledId"
`
type CreateWorkflowRunTriggeredByParams struct {
@@ -488,11 +488,12 @@ func (q *Queries) CreateWorkflowRunTriggeredBy(ctx context.Context, db DBTX, arg
&i.UpdatedAt,
&i.DeletedAt,
&i.TenantId,
&i.ParentId,
&i.Input,
&i.EventId,
&i.CronParentId,
&i.CronSchedule,
&i.ScheduledId,
&i.ParentId,
)
return &i, err
}
@@ -588,10 +589,10 @@ func (q *Queries) ListStartableStepRuns(ctx context.Context, db DBTX, arg ListSt
const listWorkflowRuns = `-- name: ListWorkflowRuns :many
SELECT
runs."createdAt", runs."updatedAt", runs."deletedAt", runs."tenantId", runs."workflowVersionId", runs.status, runs.error, runs."startedAt", runs."finishedAt", runs."concurrencyGroupId", runs."displayName", runs.id,
runs.id, runs."createdAt", runs."updatedAt", runs."deletedAt", runs."displayName", runs."tenantId", runs."workflowVersionId", runs."concurrencyGroupId", runs.status, runs.error, runs."startedAt", runs."finishedAt",
workflow.id, workflow."createdAt", workflow."updatedAt", workflow."deletedAt", workflow."tenantId", workflow.name, workflow.description,
runtriggers.id, runtriggers."createdAt", runtriggers."updatedAt", runtriggers."deletedAt", runtriggers."tenantId", runtriggers."eventId", runtriggers."cronParentId", runtriggers."cronSchedule", runtriggers."scheduledId", runtriggers."parentId",
workflowversion.id, workflowversion."createdAt", workflowversion."updatedAt", workflowversion."deletedAt", workflowversion.version, workflowversion."order", workflowversion."workflowId", workflowversion.checksum,
runtriggers.id, runtriggers."createdAt", runtriggers."updatedAt", runtriggers."deletedAt", runtriggers."tenantId", runtriggers."parentId", runtriggers.input, runtriggers."eventId", runtriggers."cronParentId", runtriggers."cronSchedule", runtriggers."scheduledId",
workflowversion.id, workflowversion."createdAt", workflowversion."updatedAt", workflowversion."deletedAt", workflowversion.checksum, workflowversion.version, workflowversion."order", workflowversion."workflowId",
-- waiting on https://github.com/sqlc-dev/sqlc/pull/2858 for nullable events field
events.id, events.key, events."createdAt", events."updatedAt"
FROM
@@ -678,18 +679,18 @@ func (q *Queries) ListWorkflowRuns(ctx context.Context, db DBTX, arg ListWorkflo
for rows.Next() {
var i ListWorkflowRunsRow
if err := rows.Scan(
&i.WorkflowRun.ID,
&i.WorkflowRun.CreatedAt,
&i.WorkflowRun.UpdatedAt,
&i.WorkflowRun.DeletedAt,
&i.WorkflowRun.DisplayName,
&i.WorkflowRun.TenantId,
&i.WorkflowRun.WorkflowVersionId,
&i.WorkflowRun.ConcurrencyGroupId,
&i.WorkflowRun.Status,
&i.WorkflowRun.Error,
&i.WorkflowRun.StartedAt,
&i.WorkflowRun.FinishedAt,
&i.WorkflowRun.ConcurrencyGroupId,
&i.WorkflowRun.DisplayName,
&i.WorkflowRun.ID,
&i.Workflow.ID,
&i.Workflow.CreatedAt,
&i.Workflow.UpdatedAt,
@@ -702,19 +703,20 @@ func (q *Queries) ListWorkflowRuns(ctx context.Context, db DBTX, arg ListWorkflo
&i.WorkflowRunTriggeredBy.UpdatedAt,
&i.WorkflowRunTriggeredBy.DeletedAt,
&i.WorkflowRunTriggeredBy.TenantId,
&i.WorkflowRunTriggeredBy.ParentId,
&i.WorkflowRunTriggeredBy.Input,
&i.WorkflowRunTriggeredBy.EventId,
&i.WorkflowRunTriggeredBy.CronParentId,
&i.WorkflowRunTriggeredBy.CronSchedule,
&i.WorkflowRunTriggeredBy.ScheduledId,
&i.WorkflowRunTriggeredBy.ParentId,
&i.WorkflowVersion.ID,
&i.WorkflowVersion.CreatedAt,
&i.WorkflowVersion.UpdatedAt,
&i.WorkflowVersion.DeletedAt,
&i.WorkflowVersion.Checksum,
&i.WorkflowVersion.Version,
&i.WorkflowVersion.Order,
&i.WorkflowVersion.WorkflowId,
&i.WorkflowVersion.Checksum,
&i.ID,
&i.Key,
&i.CreatedAt,
@@ -779,7 +781,7 @@ WHERE "id" = (
FROM "JobRun"
WHERE "id" = $1::uuid
) AND "tenantId" = $2::uuid
RETURNING "WorkflowRun"."createdAt", "WorkflowRun"."updatedAt", "WorkflowRun"."deletedAt", "WorkflowRun"."tenantId", "WorkflowRun"."workflowVersionId", "WorkflowRun".status, "WorkflowRun".error, "WorkflowRun"."startedAt", "WorkflowRun"."finishedAt", "WorkflowRun"."concurrencyGroupId", "WorkflowRun"."displayName", "WorkflowRun".id
RETURNING "WorkflowRun".id, "WorkflowRun"."createdAt", "WorkflowRun"."updatedAt", "WorkflowRun"."deletedAt", "WorkflowRun"."displayName", "WorkflowRun"."tenantId", "WorkflowRun"."workflowVersionId", "WorkflowRun"."concurrencyGroupId", "WorkflowRun".status, "WorkflowRun".error, "WorkflowRun"."startedAt", "WorkflowRun"."finishedAt"
`
type ResolveWorkflowRunStatusParams struct {
@@ -791,18 +793,18 @@ func (q *Queries) ResolveWorkflowRunStatus(ctx context.Context, db DBTX, arg Res
row := db.QueryRow(ctx, resolveWorkflowRunStatus, arg.Jobrunid, arg.Tenantid)
var i WorkflowRun
err := row.Scan(
&i.ID,
&i.CreatedAt,
&i.UpdatedAt,
&i.DeletedAt,
&i.DisplayName,
&i.TenantId,
&i.WorkflowVersionId,
&i.ConcurrencyGroupId,
&i.Status,
&i.Error,
&i.StartedAt,
&i.FinishedAt,
&i.ConcurrencyGroupId,
&i.DisplayName,
&i.ID,
)
return &i, err
}
@@ -836,7 +838,7 @@ FROM
WHERE
workflowRun."id" = groupKeyRun."workflowRunId" AND
workflowRun."tenantId" = $1::uuid
RETURNING workflowrun."createdAt", workflowrun."updatedAt", workflowrun."deletedAt", workflowrun."tenantId", workflowrun."workflowVersionId", workflowrun.status, workflowrun.error, workflowrun."startedAt", workflowrun."finishedAt", workflowrun."concurrencyGroupId", workflowrun."displayName", workflowrun.id
RETURNING workflowrun.id, workflowrun."createdAt", workflowrun."updatedAt", workflowrun."deletedAt", workflowrun."displayName", workflowrun."tenantId", workflowrun."workflowVersionId", workflowrun."concurrencyGroupId", workflowrun.status, workflowrun.error, workflowrun."startedAt", workflowrun."finishedAt"
`
type UpdateWorkflowRunGroupKeyParams struct {
@@ -848,18 +850,18 @@ func (q *Queries) UpdateWorkflowRunGroupKey(ctx context.Context, db DBTX, arg Up
row := db.QueryRow(ctx, updateWorkflowRunGroupKey, arg.Tenantid, arg.Groupkeyrunid)
var i WorkflowRun
err := row.Scan(
&i.ID,
&i.CreatedAt,
&i.UpdatedAt,
&i.DeletedAt,
&i.DisplayName,
&i.TenantId,
&i.WorkflowVersionId,
&i.ConcurrencyGroupId,
&i.Status,
&i.Error,
&i.StartedAt,
&i.FinishedAt,
&i.ConcurrencyGroupId,
&i.DisplayName,
&i.ID,
)
return &i, err
}
@@ -466,7 +466,7 @@ INSERT INTO "WorkflowVersion" (
$5::text,
$6::text,
$7::uuid
) RETURNING id, "createdAt", "updatedAt", "deletedAt", version, "order", "workflowId", checksum
) RETURNING id, "createdAt", "updatedAt", "deletedAt", checksum, version, "order", "workflowId"
`
type CreateWorkflowVersionParams struct {
@@ -495,10 +495,10 @@ func (q *Queries) CreateWorkflowVersion(ctx context.Context, db DBTX, arg Create
&i.CreatedAt,
&i.UpdatedAt,
&i.DeletedAt,
&i.Checksum,
&i.Version,
&i.Order,
&i.WorkflowId,
&i.Checksum,
)
return &i, err
}
@@ -513,7 +513,7 @@ FROM (
"Workflow" as workflows
LEFT JOIN
(
SELECT id, "createdAt", "updatedAt", "deletedAt", version, "order", "workflowId", checksum FROM "WorkflowVersion" as workflowVersion ORDER BY workflowVersion."order" DESC LIMIT 1
SELECT id, "createdAt", "updatedAt", "deletedAt", checksum, version, "order", "workflowId" FROM "WorkflowVersion" as workflowVersion ORDER BY workflowVersion."order" DESC LIMIT 1
) as workflowVersion ON workflows."id" = workflowVersion."workflowId"
LEFT JOIN
"WorkflowTriggers" as workflowTrigger ON workflowVersion."id" = workflowTrigger."workflowVersionId"
@@ -607,7 +607,7 @@ func (q *Queries) ListWorkflows(ctx context.Context, db DBTX, arg ListWorkflowsP
const listWorkflowsLatestRuns = `-- name: ListWorkflowsLatestRuns :many
SELECT
DISTINCT ON (workflow."id") runs."createdAt", runs."updatedAt", runs."deletedAt", runs."tenantId", runs."workflowVersionId", runs.status, runs.error, runs."startedAt", runs."finishedAt", runs."concurrencyGroupId", runs."displayName", runs.id, workflow."id" as "workflowId"
DISTINCT ON (workflow."id") runs.id, runs."createdAt", runs."updatedAt", runs."deletedAt", runs."displayName", runs."tenantId", runs."workflowVersionId", runs."concurrencyGroupId", runs.status, runs.error, runs."startedAt", runs."finishedAt", workflow."id" as "workflowId"
FROM
"WorkflowRun" as runs
LEFT JOIN
@@ -666,18 +666,18 @@ func (q *Queries) ListWorkflowsLatestRuns(ctx context.Context, db DBTX, arg List
for rows.Next() {
var i ListWorkflowsLatestRunsRow
if err := rows.Scan(
&i.WorkflowRun.ID,
&i.WorkflowRun.CreatedAt,
&i.WorkflowRun.UpdatedAt,
&i.WorkflowRun.DeletedAt,
&i.WorkflowRun.DisplayName,
&i.WorkflowRun.TenantId,
&i.WorkflowRun.WorkflowVersionId,
&i.WorkflowRun.ConcurrencyGroupId,
&i.WorkflowRun.Status,
&i.WorkflowRun.Error,
&i.WorkflowRun.StartedAt,
&i.WorkflowRun.FinishedAt,
&i.WorkflowRun.ConcurrencyGroupId,
&i.WorkflowRun.DisplayName,
&i.WorkflowRun.ID,
&i.WorkflowId,
); err != nil {
return nil, err
@@ -706,7 +706,7 @@ SET
"tenantId" = EXCLUDED."tenantId"
WHERE
"Action"."tenantId" = $2 AND "Action"."actionId" = LOWER($1::text)
RETURNING description, "tenantId", "actionId", id
RETURNING id, "actionId", description, "tenantId"
`
type UpsertActionParams struct {
@@ -718,10 +718,10 @@ func (q *Queries) UpsertAction(ctx context.Context, db DBTX, arg UpsertActionPar
row := db.QueryRow(ctx, upsertAction, arg.Action, arg.Tenantid)
var i Action
err := row.Scan(
&i.ID,
&i.ActionId,
&i.Description,
&i.TenantId,
&i.ActionId,
&i.ID,
)
return &i, err
}
+27 -4
View File
@@ -18,15 +18,17 @@ type CreateWorkflowRunOpts struct {
// (required) the workflow version id
WorkflowVersionId string `validate:"required,uuid"`
ManualTriggerInput *string `validate:"omitnil,required_without=TriggeringEventId,required_without=Cron,required_without=ScheduledWorkflowId,excluded_with=TriggeringEventId,excluded_with=Cron,excluded_with=ScheduledWorkflowId"`
// (optional) the event id that triggered the workflow run
TriggeringEventId *string `validate:"omitnil,uuid,required_without=Cron,required_without=ScheduledWorkflowId,excluded_with=Cron,excluded_with=ScheduledWorkflowId"`
TriggeringEventId *string `validate:"omitnil,uuid,required_without=ManualTriggerInput,required_without=Cron,required_without=ScheduledWorkflowId,excluded_with=ManualTriggerInput,excluded_with=Cron,excluded_with=ScheduledWorkflowId"`
// (optional) the cron schedule that triggered the workflow run
Cron *string `validate:"omitnil,cron,required_without=TriggeringEventId,required_without=ScheduledWorkflowId,excluded_with=TriggeringEventId,excluded_with=ScheduledWorkflowId"`
CronParentId *string `validate:"omitnil,uuid,required_without=TriggeringEventId,required_without=ScheduledWorkflowId,excluded_with=TriggeringEventId,excluded_with=ScheduledWorkflowId"`
Cron *string `validate:"omitnil,cron,required_without=ManualTriggerInput,required_without=TriggeringEventId,required_without=ScheduledWorkflowId,excluded_with=ManualTriggerInput,excluded_with=TriggeringEventId,excluded_with=ScheduledWorkflowId"`
CronParentId *string `validate:"omitnil,uuid,required_without=ManualTriggerInput,required_without=TriggeringEventId,required_without=ScheduledWorkflowId,excluded_with=ManualTriggerInput,excluded_with=TriggeringEventId,excluded_with=ScheduledWorkflowId"`
// (optional) the scheduled trigger
ScheduledWorkflowId *string `validate:"omitnil,uuid,required_without=TriggeringEventId,required_without=Cron,excluded_with=TriggeringEventId,excluded_with=Cron"`
ScheduledWorkflowId *string `validate:"omitnil,uuid,required_without=ManualTriggerInput,required_without=TriggeringEventId,required_without=Cron,excluded_with=ManualTriggerInput,excluded_with=TriggeringEventId,excluded_with=Cron"`
// (required) the workflow jobs
JobRuns []CreateWorkflowJobRunOpts `validate:"required,min=1,dive"`
@@ -39,6 +41,27 @@ type CreateGroupKeyRunOpts struct {
Input []byte
}
func GetCreateWorkflowRunOptsFromManual(workflowVersion *db.WorkflowVersionModel, input []byte) (*CreateWorkflowRunOpts, error) {
opts := &CreateWorkflowRunOpts{
DisplayName: StringPtr(getWorkflowRunDisplayName(workflowVersion)),
WorkflowVersionId: workflowVersion.ID,
ManualTriggerInput: StringPtr(string(input)),
}
jobRunData := input
if _, hasConcurrency := workflowVersion.Concurrency(); hasConcurrency {
opts.GetGroupKeyRun = &CreateGroupKeyRunOpts{
Input: jobRunData,
}
}
var err error
opts.JobRuns, err = getJobsFromWorkflowVersion(workflowVersion, datautils.TriggeredBySchedule, jobRunData)
return opts, err
}
func GetCreateWorkflowRunOptsFromEvent(event *db.EventModel, workflowVersion *db.WorkflowVersionModel) (*CreateWorkflowRunOpts, error) {
eventId := event.ID
+212 -68
View File
@@ -1370,6 +1370,109 @@ func (x *GetWorkflowByNameRequest) GetName() string {
return ""
}
type TriggerWorkflowRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
// (optional) the input data for the workflow
Input string `protobuf:"bytes,2,opt,name=input,proto3" json:"input,omitempty"`
}
func (x *TriggerWorkflowRequest) Reset() {
*x = TriggerWorkflowRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_workflows_proto_msgTypes[18]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *TriggerWorkflowRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*TriggerWorkflowRequest) ProtoMessage() {}
func (x *TriggerWorkflowRequest) ProtoReflect() protoreflect.Message {
mi := &file_workflows_proto_msgTypes[18]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use TriggerWorkflowRequest.ProtoReflect.Descriptor instead.
func (*TriggerWorkflowRequest) Descriptor() ([]byte, []int) {
return file_workflows_proto_rawDescGZIP(), []int{18}
}
func (x *TriggerWorkflowRequest) GetName() string {
if x != nil {
return x.Name
}
return ""
}
func (x *TriggerWorkflowRequest) GetInput() string {
if x != nil {
return x.Input
}
return ""
}
type TriggerWorkflowResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
WorkflowRunId string `protobuf:"bytes,1,opt,name=workflow_run_id,json=workflowRunId,proto3" json:"workflow_run_id,omitempty"`
}
func (x *TriggerWorkflowResponse) Reset() {
*x = TriggerWorkflowResponse{}
if protoimpl.UnsafeEnabled {
mi := &file_workflows_proto_msgTypes[19]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *TriggerWorkflowResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*TriggerWorkflowResponse) ProtoMessage() {}
func (x *TriggerWorkflowResponse) ProtoReflect() protoreflect.Message {
mi := &file_workflows_proto_msgTypes[19]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use TriggerWorkflowResponse.ProtoReflect.Descriptor instead.
func (*TriggerWorkflowResponse) Descriptor() ([]byte, []int) {
return file_workflows_proto_rawDescGZIP(), []int{19}
}
func (x *TriggerWorkflowResponse) GetWorkflowRunId() string {
if x != nil {
return x.WorkflowRunId
}
return ""
}
var File_workflows_proto protoreflect.FileDescriptor
var file_workflows_proto_rawDesc = []byte{
@@ -1576,42 +1679,55 @@ var file_workflows_proto_rawDesc = []byte{
0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x49, 0x64, 0x22, 0x2e, 0x0a, 0x18, 0x47, 0x65, 0x74, 0x57,
0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x42, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x52, 0x65, 0x71,
0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01,
0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x2a, 0x55, 0x0a, 0x18, 0x43, 0x6f, 0x6e, 0x63,
0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x53, 0x74, 0x72, 0x61,
0x74, 0x65, 0x67, 0x79, 0x12, 0x16, 0x0a, 0x12, 0x43, 0x41, 0x4e, 0x43, 0x45, 0x4c, 0x5f, 0x49,
0x4e, 0x5f, 0x50, 0x52, 0x4f, 0x47, 0x52, 0x45, 0x53, 0x53, 0x10, 0x00, 0x12, 0x0f, 0x0a, 0x0b,
0x44, 0x52, 0x4f, 0x50, 0x5f, 0x4e, 0x45, 0x57, 0x45, 0x53, 0x54, 0x10, 0x01, 0x12, 0x10, 0x0a,
0x0c, 0x51, 0x55, 0x45, 0x55, 0x45, 0x5f, 0x4e, 0x45, 0x57, 0x45, 0x53, 0x54, 0x10, 0x02, 0x32,
0x87, 0x03, 0x0a, 0x0f, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x53, 0x65, 0x72, 0x76,
0x69, 0x63, 0x65, 0x12, 0x3e, 0x0a, 0x0d, 0x4c, 0x69, 0x73, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x66,
0x6c, 0x6f, 0x77, 0x73, 0x12, 0x15, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x66,
0x6c, 0x6f, 0x77, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x4c, 0x69,
0x73, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f,
0x6e, 0x73, 0x65, 0x12, 0x34, 0x0a, 0x0b, 0x50, 0x75, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c,
0x6f, 0x77, 0x12, 0x13, 0x2e, 0x50, 0x75, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77,
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x10, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c,
0x6f, 0x77, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x3e, 0x0a, 0x10, 0x53, 0x63, 0x68,
0x65, 0x64, 0x75, 0x6c, 0x65, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x12, 0x18, 0x2e,
0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77,
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x10, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c,
0x6f, 0x77, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x39, 0x0a, 0x11, 0x47, 0x65, 0x74,
0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x42, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x19,
0x2e, 0x47, 0x65, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x42, 0x79, 0x4e, 0x61,
0x6d, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x09, 0x2e, 0x57, 0x6f, 0x72, 0x6b,
0x66, 0x6c, 0x6f, 0x77, 0x12, 0x4e, 0x0a, 0x15, 0x4c, 0x69, 0x73, 0x74, 0x57, 0x6f, 0x72, 0x6b,
0x66, 0x6c, 0x6f, 0x77, 0x73, 0x46, 0x6f, 0x72, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x1d, 0x2e,
0x4c, 0x69, 0x73, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x73, 0x46, 0x6f, 0x72,
0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x4c,
0x69, 0x73, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x73, 0x52, 0x65, 0x73, 0x70,
0x6f, 0x6e, 0x73, 0x65, 0x12, 0x33, 0x0a, 0x0e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x57, 0x6f,
0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x12, 0x16, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x57,
0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x09,
0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x42, 0x42, 0x5a, 0x40, 0x67, 0x69, 0x74,
0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61, 0x74, 0x63, 0x68, 0x65, 0x74, 0x2d,
0x64, 0x65, 0x76, 0x2f, 0x68, 0x61, 0x74, 0x63, 0x68, 0x65, 0x74, 0x2f, 0x69, 0x6e, 0x74, 0x65,
0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2f, 0x61, 0x64,
0x6d, 0x69, 0x6e, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x73, 0x62, 0x06, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x33,
0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x42, 0x0a, 0x16, 0x54, 0x72, 0x69, 0x67,
0x67, 0x65, 0x72, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x52, 0x65, 0x71, 0x75, 0x65,
0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x18,
0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x22, 0x41, 0x0a, 0x17,
0x54, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x52,
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x26, 0x0a, 0x0f, 0x77, 0x6f, 0x72, 0x6b, 0x66,
0x6c, 0x6f, 0x77, 0x5f, 0x72, 0x75, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
0x52, 0x0d, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x52, 0x75, 0x6e, 0x49, 0x64, 0x2a,
0x55, 0x0a, 0x18, 0x43, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x4c, 0x69,
0x6d, 0x69, 0x74, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x16, 0x0a, 0x12, 0x43,
0x41, 0x4e, 0x43, 0x45, 0x4c, 0x5f, 0x49, 0x4e, 0x5f, 0x50, 0x52, 0x4f, 0x47, 0x52, 0x45, 0x53,
0x53, 0x10, 0x00, 0x12, 0x0f, 0x0a, 0x0b, 0x44, 0x52, 0x4f, 0x50, 0x5f, 0x4e, 0x45, 0x57, 0x45,
0x53, 0x54, 0x10, 0x01, 0x12, 0x10, 0x0a, 0x0c, 0x51, 0x55, 0x45, 0x55, 0x45, 0x5f, 0x4e, 0x45,
0x57, 0x45, 0x53, 0x54, 0x10, 0x02, 0x32, 0xcd, 0x03, 0x0a, 0x0f, 0x57, 0x6f, 0x72, 0x6b, 0x66,
0x6c, 0x6f, 0x77, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x3e, 0x0a, 0x0d, 0x4c, 0x69,
0x73, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x73, 0x12, 0x15, 0x2e, 0x4c, 0x69,
0x73, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65,
0x73, 0x74, 0x1a, 0x16, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f,
0x77, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x34, 0x0a, 0x0b, 0x50, 0x75,
0x74, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x12, 0x13, 0x2e, 0x50, 0x75, 0x74, 0x57,
0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x10,
0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e,
0x12, 0x3e, 0x0a, 0x10, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x57, 0x6f, 0x72, 0x6b,
0x66, 0x6c, 0x6f, 0x77, 0x12, 0x18, 0x2e, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x57,
0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x10,
0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e,
0x12, 0x44, 0x0a, 0x0f, 0x54, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x57, 0x6f, 0x72, 0x6b, 0x66,
0x6c, 0x6f, 0x77, 0x12, 0x17, 0x2e, 0x54, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x57, 0x6f, 0x72,
0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x54,
0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x52, 0x65,
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x39, 0x0a, 0x11, 0x47, 0x65, 0x74, 0x57, 0x6f, 0x72,
0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x42, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x19, 0x2e, 0x47, 0x65,
0x74, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x42, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x52,
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x09, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f,
0x77, 0x12, 0x4e, 0x0a, 0x15, 0x4c, 0x69, 0x73, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f,
0x77, 0x73, 0x46, 0x6f, 0x72, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x1d, 0x2e, 0x4c, 0x69, 0x73,
0x74, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x73, 0x46, 0x6f, 0x72, 0x45, 0x76, 0x65,
0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x4c, 0x69, 0x73, 0x74,
0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
0x65, 0x12, 0x33, 0x0a, 0x0e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x57, 0x6f, 0x72, 0x6b, 0x66,
0x6c, 0x6f, 0x77, 0x12, 0x16, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x57, 0x6f, 0x72, 0x6b,
0x66, 0x6c, 0x6f, 0x77, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x09, 0x2e, 0x57, 0x6f,
0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x42, 0x42, 0x5a, 0x40, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62,
0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61, 0x74, 0x63, 0x68, 0x65, 0x74, 0x2d, 0x64, 0x65, 0x76,
0x2f, 0x68, 0x61, 0x74, 0x63, 0x68, 0x65, 0x74, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61,
0x6c, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2f, 0x61, 0x64, 0x6d, 0x69, 0x6e,
0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x33,
}
var (
@@ -1627,7 +1743,7 @@ func file_workflows_proto_rawDescGZIP() []byte {
}
var file_workflows_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
var file_workflows_proto_msgTypes = make([]protoimpl.MessageInfo, 18)
var file_workflows_proto_msgTypes = make([]protoimpl.MessageInfo, 20)
var file_workflows_proto_goTypes = []interface{}{
(ConcurrencyLimitStrategy)(0), // 0: ConcurrencyLimitStrategy
(*PutWorkflowRequest)(nil), // 1: PutWorkflowRequest
@@ -1648,53 +1764,57 @@ var file_workflows_proto_goTypes = []interface{}{
(*Step)(nil), // 16: Step
(*DeleteWorkflowRequest)(nil), // 17: DeleteWorkflowRequest
(*GetWorkflowByNameRequest)(nil), // 18: GetWorkflowByNameRequest
(*timestamppb.Timestamp)(nil), // 19: google.protobuf.Timestamp
(*wrapperspb.StringValue)(nil), // 20: google.protobuf.StringValue
(*TriggerWorkflowRequest)(nil), // 19: TriggerWorkflowRequest
(*TriggerWorkflowResponse)(nil), // 20: TriggerWorkflowResponse
(*timestamppb.Timestamp)(nil), // 21: google.protobuf.Timestamp
(*wrapperspb.StringValue)(nil), // 22: google.protobuf.StringValue
}
var file_workflows_proto_depIdxs = []int32{
2, // 0: PutWorkflowRequest.opts:type_name -> CreateWorkflowVersionOpts
19, // 1: CreateWorkflowVersionOpts.scheduled_triggers:type_name -> google.protobuf.Timestamp
21, // 1: CreateWorkflowVersionOpts.scheduled_triggers:type_name -> google.protobuf.Timestamp
4, // 2: CreateWorkflowVersionOpts.jobs:type_name -> CreateWorkflowJobOpts
3, // 3: CreateWorkflowVersionOpts.concurrency:type_name -> WorkflowConcurrencyOpts
0, // 4: WorkflowConcurrencyOpts.limit_strategy:type_name -> ConcurrencyLimitStrategy
5, // 5: CreateWorkflowJobOpts.steps:type_name -> CreateWorkflowStepOpts
19, // 6: ScheduleWorkflowRequest.schedules:type_name -> google.protobuf.Timestamp
21, // 6: ScheduleWorkflowRequest.schedules:type_name -> google.protobuf.Timestamp
10, // 7: ListWorkflowsResponse.workflows:type_name -> Workflow
19, // 8: Workflow.created_at:type_name -> google.protobuf.Timestamp
19, // 9: Workflow.updated_at:type_name -> google.protobuf.Timestamp
20, // 10: Workflow.description:type_name -> google.protobuf.StringValue
21, // 8: Workflow.created_at:type_name -> google.protobuf.Timestamp
21, // 9: Workflow.updated_at:type_name -> google.protobuf.Timestamp
22, // 10: Workflow.description:type_name -> google.protobuf.StringValue
11, // 11: Workflow.versions:type_name -> WorkflowVersion
19, // 12: WorkflowVersion.created_at:type_name -> google.protobuf.Timestamp
19, // 13: WorkflowVersion.updated_at:type_name -> google.protobuf.Timestamp
21, // 12: WorkflowVersion.created_at:type_name -> google.protobuf.Timestamp
21, // 13: WorkflowVersion.updated_at:type_name -> google.protobuf.Timestamp
12, // 14: WorkflowVersion.triggers:type_name -> WorkflowTriggers
15, // 15: WorkflowVersion.jobs:type_name -> Job
19, // 16: WorkflowTriggers.created_at:type_name -> google.protobuf.Timestamp
19, // 17: WorkflowTriggers.updated_at:type_name -> google.protobuf.Timestamp
21, // 16: WorkflowTriggers.created_at:type_name -> google.protobuf.Timestamp
21, // 17: WorkflowTriggers.updated_at:type_name -> google.protobuf.Timestamp
13, // 18: WorkflowTriggers.events:type_name -> WorkflowTriggerEventRef
14, // 19: WorkflowTriggers.crons:type_name -> WorkflowTriggerCronRef
19, // 20: Job.created_at:type_name -> google.protobuf.Timestamp
19, // 21: Job.updated_at:type_name -> google.protobuf.Timestamp
20, // 22: Job.description:type_name -> google.protobuf.StringValue
21, // 20: Job.created_at:type_name -> google.protobuf.Timestamp
21, // 21: Job.updated_at:type_name -> google.protobuf.Timestamp
22, // 22: Job.description:type_name -> google.protobuf.StringValue
16, // 23: Job.steps:type_name -> Step
20, // 24: Job.timeout:type_name -> google.protobuf.StringValue
19, // 25: Step.created_at:type_name -> google.protobuf.Timestamp
19, // 26: Step.updated_at:type_name -> google.protobuf.Timestamp
20, // 27: Step.readable_id:type_name -> google.protobuf.StringValue
20, // 28: Step.timeout:type_name -> google.protobuf.StringValue
22, // 24: Job.timeout:type_name -> google.protobuf.StringValue
21, // 25: Step.created_at:type_name -> google.protobuf.Timestamp
21, // 26: Step.updated_at:type_name -> google.protobuf.Timestamp
22, // 27: Step.readable_id:type_name -> google.protobuf.StringValue
22, // 28: Step.timeout:type_name -> google.protobuf.StringValue
6, // 29: WorkflowService.ListWorkflows:input_type -> ListWorkflowsRequest
1, // 30: WorkflowService.PutWorkflow:input_type -> PutWorkflowRequest
7, // 31: WorkflowService.ScheduleWorkflow:input_type -> ScheduleWorkflowRequest
18, // 32: WorkflowService.GetWorkflowByName:input_type -> GetWorkflowByNameRequest
9, // 33: WorkflowService.ListWorkflowsForEvent:input_type -> ListWorkflowsForEventRequest
17, // 34: WorkflowService.DeleteWorkflow:input_type -> DeleteWorkflowRequest
8, // 35: WorkflowService.ListWorkflows:output_type -> ListWorkflowsResponse
11, // 36: WorkflowService.PutWorkflow:output_type -> WorkflowVersion
11, // 37: WorkflowService.ScheduleWorkflow:output_type -> WorkflowVersion
10, // 38: WorkflowService.GetWorkflowByName:output_type -> Workflow
8, // 39: WorkflowService.ListWorkflowsForEvent:output_type -> ListWorkflowsResponse
10, // 40: WorkflowService.DeleteWorkflow:output_type -> Workflow
35, // [35:41] is the sub-list for method output_type
29, // [29:35] is the sub-list for method input_type
19, // 32: WorkflowService.TriggerWorkflow:input_type -> TriggerWorkflowRequest
18, // 33: WorkflowService.GetWorkflowByName:input_type -> GetWorkflowByNameRequest
9, // 34: WorkflowService.ListWorkflowsForEvent:input_type -> ListWorkflowsForEventRequest
17, // 35: WorkflowService.DeleteWorkflow:input_type -> DeleteWorkflowRequest
8, // 36: WorkflowService.ListWorkflows:output_type -> ListWorkflowsResponse
11, // 37: WorkflowService.PutWorkflow:output_type -> WorkflowVersion
11, // 38: WorkflowService.ScheduleWorkflow:output_type -> WorkflowVersion
20, // 39: WorkflowService.TriggerWorkflow:output_type -> TriggerWorkflowResponse
10, // 40: WorkflowService.GetWorkflowByName:output_type -> Workflow
8, // 41: WorkflowService.ListWorkflowsForEvent:output_type -> ListWorkflowsResponse
10, // 42: WorkflowService.DeleteWorkflow:output_type -> Workflow
36, // [36:43] is the sub-list for method output_type
29, // [29:36] is the sub-list for method input_type
29, // [29:29] is the sub-list for extension type_name
29, // [29:29] is the sub-list for extension extendee
0, // [0:29] is the sub-list for field type_name
@@ -1922,6 +2042,30 @@ func file_workflows_proto_init() {
return nil
}
}
file_workflows_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*TriggerWorkflowRequest); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_workflows_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*TriggerWorkflowResponse); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
@@ -1929,7 +2073,7 @@ func file_workflows_proto_init() {
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_workflows_proto_rawDesc,
NumEnums: 1,
NumMessages: 18,
NumMessages: 20,
NumExtensions: 0,
NumServices: 1,
},
@@ -25,6 +25,7 @@ type WorkflowServiceClient interface {
ListWorkflows(ctx context.Context, in *ListWorkflowsRequest, opts ...grpc.CallOption) (*ListWorkflowsResponse, error)
PutWorkflow(ctx context.Context, in *PutWorkflowRequest, opts ...grpc.CallOption) (*WorkflowVersion, error)
ScheduleWorkflow(ctx context.Context, in *ScheduleWorkflowRequest, opts ...grpc.CallOption) (*WorkflowVersion, error)
TriggerWorkflow(ctx context.Context, in *TriggerWorkflowRequest, opts ...grpc.CallOption) (*TriggerWorkflowResponse, error)
GetWorkflowByName(ctx context.Context, in *GetWorkflowByNameRequest, opts ...grpc.CallOption) (*Workflow, error)
ListWorkflowsForEvent(ctx context.Context, in *ListWorkflowsForEventRequest, opts ...grpc.CallOption) (*ListWorkflowsResponse, error)
DeleteWorkflow(ctx context.Context, in *DeleteWorkflowRequest, opts ...grpc.CallOption) (*Workflow, error)
@@ -65,6 +66,15 @@ func (c *workflowServiceClient) ScheduleWorkflow(ctx context.Context, in *Schedu
return out, nil
}
func (c *workflowServiceClient) TriggerWorkflow(ctx context.Context, in *TriggerWorkflowRequest, opts ...grpc.CallOption) (*TriggerWorkflowResponse, error) {
out := new(TriggerWorkflowResponse)
err := c.cc.Invoke(ctx, "/WorkflowService/TriggerWorkflow", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *workflowServiceClient) GetWorkflowByName(ctx context.Context, in *GetWorkflowByNameRequest, opts ...grpc.CallOption) (*Workflow, error) {
out := new(Workflow)
err := c.cc.Invoke(ctx, "/WorkflowService/GetWorkflowByName", in, out, opts...)
@@ -99,6 +109,7 @@ type WorkflowServiceServer interface {
ListWorkflows(context.Context, *ListWorkflowsRequest) (*ListWorkflowsResponse, error)
PutWorkflow(context.Context, *PutWorkflowRequest) (*WorkflowVersion, error)
ScheduleWorkflow(context.Context, *ScheduleWorkflowRequest) (*WorkflowVersion, error)
TriggerWorkflow(context.Context, *TriggerWorkflowRequest) (*TriggerWorkflowResponse, error)
GetWorkflowByName(context.Context, *GetWorkflowByNameRequest) (*Workflow, error)
ListWorkflowsForEvent(context.Context, *ListWorkflowsForEventRequest) (*ListWorkflowsResponse, error)
DeleteWorkflow(context.Context, *DeleteWorkflowRequest) (*Workflow, error)
@@ -118,6 +129,9 @@ func (UnimplementedWorkflowServiceServer) PutWorkflow(context.Context, *PutWorkf
func (UnimplementedWorkflowServiceServer) ScheduleWorkflow(context.Context, *ScheduleWorkflowRequest) (*WorkflowVersion, error) {
return nil, status.Errorf(codes.Unimplemented, "method ScheduleWorkflow not implemented")
}
func (UnimplementedWorkflowServiceServer) TriggerWorkflow(context.Context, *TriggerWorkflowRequest) (*TriggerWorkflowResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method TriggerWorkflow not implemented")
}
func (UnimplementedWorkflowServiceServer) GetWorkflowByName(context.Context, *GetWorkflowByNameRequest) (*Workflow, error) {
return nil, status.Errorf(codes.Unimplemented, "method GetWorkflowByName not implemented")
}
@@ -194,6 +208,24 @@ func _WorkflowService_ScheduleWorkflow_Handler(srv interface{}, ctx context.Cont
return interceptor(ctx, in, info, handler)
}
func _WorkflowService_TriggerWorkflow_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(TriggerWorkflowRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(WorkflowServiceServer).TriggerWorkflow(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/WorkflowService/TriggerWorkflow",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(WorkflowServiceServer).TriggerWorkflow(ctx, req.(*TriggerWorkflowRequest))
}
return interceptor(ctx, in, info, handler)
}
func _WorkflowService_GetWorkflowByName_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(GetWorkflowByNameRequest)
if err := dec(in); err != nil {
@@ -267,6 +299,10 @@ var WorkflowService_ServiceDesc = grpc.ServiceDesc{
MethodName: "ScheduleWorkflow",
Handler: _WorkflowService_ScheduleWorkflow_Handler,
},
{
MethodName: "TriggerWorkflow",
Handler: _WorkflowService_TriggerWorkflow_Handler,
},
{
MethodName: "GetWorkflowByName",
Handler: _WorkflowService_GetWorkflowByName_Handler,
+49 -4
View File
@@ -45,6 +45,55 @@ func (a *AdminServiceImpl) GetWorkflowByName(ctx context.Context, req *contracts
return resp, nil
}
func (a *AdminServiceImpl) TriggerWorkflow(ctx context.Context, req *contracts.TriggerWorkflowRequest) (*contracts.TriggerWorkflowResponse, error) {
tenant := ctx.Value("tenant").(*db.TenantModel)
workflow, err := a.repo.Workflow().GetWorkflowByName(
tenant.ID,
req.Name,
)
if err != nil {
if errors.Is(err, db.ErrNotFound) {
return nil, status.Error(
codes.NotFound,
"workflow not found",
)
}
return nil, err
}
workflowVersion := &workflow.Versions()[0]
if workflowVersion == nil {
return nil, fmt.Errorf("workflow with id %s has no versions", workflow.ID)
}
createOpts, err := repository.GetCreateWorkflowRunOptsFromManual(workflowVersion, []byte(req.Input))
if err != nil {
return nil, err
}
workflowRun, err := a.repo.WorkflowRun().CreateNewWorkflowRun(ctx, tenant.ID, createOpts)
if err != nil {
return nil, fmt.Errorf("could not create workflow run: %w", err)
}
// send to workflow processing queue
err = a.tq.AddTask(
context.Background(),
taskqueue.WORKFLOW_PROCESSING_QUEUE,
tasktypes.WorkflowRunQueuedToTask(workflowRun),
)
return &contracts.TriggerWorkflowResponse{
WorkflowRunId: workflowRun.ID,
}, nil
}
func (a *AdminServiceImpl) PutWorkflow(ctx context.Context, req *contracts.PutWorkflowRequest) (*contracts.WorkflowVersion, error) {
tenant := ctx.Value("tenant").(*db.TenantModel)
@@ -736,7 +785,6 @@ func cronScheduleTask(ticker *db.TickerModel, cronTriggerRef *db.WorkflowTrigger
return &taskqueue.Task{
ID: "schedule-cron",
Queue: taskqueue.QueueTypeFromTickerID(ticker.ID),
Payload: payload,
Metadata: metadata,
}, nil
@@ -755,7 +803,6 @@ func cronCancelTask(ticker *db.TickerModel, cronTriggerRef *db.WorkflowTriggerCr
return &taskqueue.Task{
ID: "cancel-cron",
Queue: taskqueue.QueueTypeFromTickerID(ticker.ID),
Payload: payload,
Metadata: metadata,
}, nil
@@ -774,7 +821,6 @@ func workflowScheduleTask(ticker *db.TickerModel, workflowTriggerRef *db.Workflo
return &taskqueue.Task{
ID: "schedule-workflow",
Queue: taskqueue.QueueTypeFromTickerID(ticker.ID),
Payload: payload,
Metadata: metadata,
}, nil
@@ -793,7 +839,6 @@ func workflowCancelTask(ticker *db.TickerModel, workflowTriggerRef *db.WorkflowT
return &taskqueue.Task{
ID: "cancel-workflow",
Queue: taskqueue.QueueTypeFromTickerID(ticker.ID),
Payload: payload,
Metadata: metadata,
}, nil
@@ -146,7 +146,7 @@ func (ec *JobsControllerImpl) handleTask(ctx context.Context, task *taskqueue.Ta
return ec.handleTickerRemoved(ctx, task)
}
return fmt.Errorf("unknown task: %s in queue %s", task.ID, string(task.Queue))
return fmt.Errorf("unknown task: %s", task.ID)
}
func (ec *JobsControllerImpl) handleJobRunQueued(ctx context.Context, task *taskqueue.Task) error {
@@ -1052,7 +1052,6 @@ func stepRunAssignedTask(tenantId, stepRunId string, worker *db.WorkerModel) *ta
return &taskqueue.Task{
ID: "step-run-assigned",
Queue: taskqueue.QueueTypeFromDispatcherID(dispatcher.ID),
Payload: payload,
Metadata: metadata,
}
@@ -1090,7 +1089,6 @@ func scheduleStepRunTimeoutTask(ticker *db.TickerModel, stepRun *db.StepRunModel
return &taskqueue.Task{
ID: "schedule-step-run-timeout",
Queue: taskqueue.QueueTypeFromTickerID(ticker.ID),
Payload: payload,
Metadata: metadata,
}, nil
@@ -1127,7 +1125,6 @@ func scheduleJobRunTimeoutTask(ticker *db.TickerModel, jobRun *db.JobRunModel) (
return &taskqueue.Task{
ID: "schedule-job-run-timeout",
Queue: taskqueue.QueueTypeFromTickerID(ticker.ID),
Payload: payload,
Metadata: metadata,
}, nil
@@ -1144,7 +1141,6 @@ func cancelStepRunTimeoutTask(ticker *db.TickerModel, stepRun *db.StepRunModel)
return &taskqueue.Task{
ID: "cancel-step-run-timeout",
Queue: taskqueue.QueueTypeFromTickerID(ticker.ID),
Payload: payload,
Metadata: metadata,
}
@@ -1166,7 +1162,6 @@ func stepRunCancelledTask(tenantId, stepRunId, cancelledReason string, worker *d
return &taskqueue.Task{
ID: "step-run-cancelled",
Queue: taskqueue.QueueTypeFromDispatcherID(dispatcher.ID),
Payload: payload,
Metadata: metadata,
}
@@ -134,7 +134,7 @@ func (wc *WorkflowsControllerImpl) handleTask(ctx context.Context, task *taskque
// return ec.handleStepRunStarted(ctx, task)
}
return fmt.Errorf("unknown task: %s in queue %s", task.ID, string(task.Queue))
return fmt.Errorf("unknown task: %s", task.ID)
}
func (ec *WorkflowsControllerImpl) handleGroupKeyRunStarted(ctx context.Context, task *taskqueue.Task) error {
@@ -314,7 +314,6 @@ func cancelGetGroupKeyRunTimeoutTask(ticker *db.TickerModel, getGroupKeyRun *db.
return &taskqueue.Task{
ID: "cancel-get-group-key-run-timeout",
Queue: taskqueue.QueueTypeFromTickerID(ticker.ID),
Payload: payload,
Metadata: metadata,
}
@@ -456,7 +456,6 @@ func getGroupActionTask(tenantId, workflowRunId string, worker *db.WorkerModel)
return &taskqueue.Task{
ID: "group-key-action-assigned",
Queue: taskqueue.QueueTypeFromDispatcherID(dispatcher.ID),
Payload: payload,
Metadata: metadata,
}
@@ -474,7 +473,6 @@ func getStepRunNotifyCancelTask(tenantId, stepRunId, reason string) *taskqueue.T
return &taskqueue.Task{
ID: "step-run-cancelled",
Queue: taskqueue.JOB_PROCESSING_QUEUE,
Payload: payload,
Metadata: metadata,
}
@@ -504,7 +502,6 @@ func scheduleGetGroupKeyRunTimeoutTask(ticker *db.TickerModel, getGroupKeyRun *d
return &taskqueue.Task{
ID: "schedule-get-group-key-run-timeout",
Queue: taskqueue.QueueTypeFromTickerID(ticker.ID),
Payload: payload,
Metadata: metadata,
}, nil
@@ -174,6 +174,113 @@ func (StepActionEventType) EnumDescriptor() ([]byte, []int) {
return file_dispatcher_proto_rawDescGZIP(), []int{2}
}
type ResourceType int32
const (
ResourceType_RESOURCE_TYPE_UNKNOWN ResourceType = 0
ResourceType_RESOURCE_TYPE_STEP_RUN ResourceType = 1
ResourceType_RESOURCE_TYPE_WORKFLOW_RUN ResourceType = 2
)
// Enum value maps for ResourceType.
var (
ResourceType_name = map[int32]string{
0: "RESOURCE_TYPE_UNKNOWN",
1: "RESOURCE_TYPE_STEP_RUN",
2: "RESOURCE_TYPE_WORKFLOW_RUN",
}
ResourceType_value = map[string]int32{
"RESOURCE_TYPE_UNKNOWN": 0,
"RESOURCE_TYPE_STEP_RUN": 1,
"RESOURCE_TYPE_WORKFLOW_RUN": 2,
}
)
func (x ResourceType) Enum() *ResourceType {
p := new(ResourceType)
*p = x
return p
}
func (x ResourceType) String() string {
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
}
func (ResourceType) Descriptor() protoreflect.EnumDescriptor {
return file_dispatcher_proto_enumTypes[3].Descriptor()
}
func (ResourceType) Type() protoreflect.EnumType {
return &file_dispatcher_proto_enumTypes[3]
}
func (x ResourceType) Number() protoreflect.EnumNumber {
return protoreflect.EnumNumber(x)
}
// Deprecated: Use ResourceType.Descriptor instead.
func (ResourceType) EnumDescriptor() ([]byte, []int) {
return file_dispatcher_proto_rawDescGZIP(), []int{3}
}
type ResourceEventType int32
const (
ResourceEventType_RESOURCE_EVENT_TYPE_UNKNOWN ResourceEventType = 0
ResourceEventType_RESOURCE_EVENT_TYPE_STARTED ResourceEventType = 1
ResourceEventType_RESOURCE_EVENT_TYPE_COMPLETED ResourceEventType = 2
ResourceEventType_RESOURCE_EVENT_TYPE_FAILED ResourceEventType = 3
ResourceEventType_RESOURCE_EVENT_TYPE_CANCELLED ResourceEventType = 4
ResourceEventType_RESOURCE_EVENT_TYPE_TIMED_OUT ResourceEventType = 5
)
// Enum value maps for ResourceEventType.
var (
ResourceEventType_name = map[int32]string{
0: "RESOURCE_EVENT_TYPE_UNKNOWN",
1: "RESOURCE_EVENT_TYPE_STARTED",
2: "RESOURCE_EVENT_TYPE_COMPLETED",
3: "RESOURCE_EVENT_TYPE_FAILED",
4: "RESOURCE_EVENT_TYPE_CANCELLED",
5: "RESOURCE_EVENT_TYPE_TIMED_OUT",
}
ResourceEventType_value = map[string]int32{
"RESOURCE_EVENT_TYPE_UNKNOWN": 0,
"RESOURCE_EVENT_TYPE_STARTED": 1,
"RESOURCE_EVENT_TYPE_COMPLETED": 2,
"RESOURCE_EVENT_TYPE_FAILED": 3,
"RESOURCE_EVENT_TYPE_CANCELLED": 4,
"RESOURCE_EVENT_TYPE_TIMED_OUT": 5,
}
)
func (x ResourceEventType) Enum() *ResourceEventType {
p := new(ResourceEventType)
*p = x
return p
}
func (x ResourceEventType) String() string {
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
}
func (ResourceEventType) Descriptor() protoreflect.EnumDescriptor {
return file_dispatcher_proto_enumTypes[4].Descriptor()
}
func (ResourceEventType) Type() protoreflect.EnumType {
return &file_dispatcher_proto_enumTypes[4]
}
func (x ResourceEventType) Number() protoreflect.EnumNumber {
return protoreflect.EnumNumber(x)
}
// Deprecated: Use ResourceEventType.Descriptor instead.
func (ResourceEventType) EnumDescriptor() ([]byte, []int) {
return file_dispatcher_proto_rawDescGZIP(), []int{4}
}
type WorkerRegisterRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
@@ -873,6 +980,143 @@ func (x *ActionEventResponse) GetWorkerId() string {
return ""
}
type SubscribeToWorkflowEventsRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// the id of the workflow run
WorkflowRunId string `protobuf:"bytes,1,opt,name=workflowRunId,proto3" json:"workflowRunId,omitempty"`
}
func (x *SubscribeToWorkflowEventsRequest) Reset() {
*x = SubscribeToWorkflowEventsRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_dispatcher_proto_msgTypes[9]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *SubscribeToWorkflowEventsRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*SubscribeToWorkflowEventsRequest) ProtoMessage() {}
func (x *SubscribeToWorkflowEventsRequest) ProtoReflect() protoreflect.Message {
mi := &file_dispatcher_proto_msgTypes[9]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use SubscribeToWorkflowEventsRequest.ProtoReflect.Descriptor instead.
func (*SubscribeToWorkflowEventsRequest) Descriptor() ([]byte, []int) {
return file_dispatcher_proto_rawDescGZIP(), []int{9}
}
func (x *SubscribeToWorkflowEventsRequest) GetWorkflowRunId() string {
if x != nil {
return x.WorkflowRunId
}
return ""
}
type WorkflowEvent struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// the id of the workflow run
WorkflowRunId string `protobuf:"bytes,1,opt,name=workflowRunId,proto3" json:"workflowRunId,omitempty"`
ResourceType ResourceType `protobuf:"varint,2,opt,name=resourceType,proto3,enum=ResourceType" json:"resourceType,omitempty"`
EventType ResourceEventType `protobuf:"varint,3,opt,name=eventType,proto3,enum=ResourceEventType" json:"eventType,omitempty"`
ResourceId string `protobuf:"bytes,4,opt,name=resourceId,proto3" json:"resourceId,omitempty"`
EventTimestamp *timestamppb.Timestamp `protobuf:"bytes,5,opt,name=eventTimestamp,proto3" json:"eventTimestamp,omitempty"`
// the event payload
EventPayload string `protobuf:"bytes,6,opt,name=eventPayload,proto3" json:"eventPayload,omitempty"`
}
func (x *WorkflowEvent) Reset() {
*x = WorkflowEvent{}
if protoimpl.UnsafeEnabled {
mi := &file_dispatcher_proto_msgTypes[10]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *WorkflowEvent) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*WorkflowEvent) ProtoMessage() {}
func (x *WorkflowEvent) ProtoReflect() protoreflect.Message {
mi := &file_dispatcher_proto_msgTypes[10]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use WorkflowEvent.ProtoReflect.Descriptor instead.
func (*WorkflowEvent) Descriptor() ([]byte, []int) {
return file_dispatcher_proto_rawDescGZIP(), []int{10}
}
func (x *WorkflowEvent) GetWorkflowRunId() string {
if x != nil {
return x.WorkflowRunId
}
return ""
}
func (x *WorkflowEvent) GetResourceType() ResourceType {
if x != nil {
return x.ResourceType
}
return ResourceType_RESOURCE_TYPE_UNKNOWN
}
func (x *WorkflowEvent) GetEventType() ResourceEventType {
if x != nil {
return x.EventType
}
return ResourceEventType_RESOURCE_EVENT_TYPE_UNKNOWN
}
func (x *WorkflowEvent) GetResourceId() string {
if x != nil {
return x.ResourceId
}
return ""
}
func (x *WorkflowEvent) GetEventTimestamp() *timestamppb.Timestamp {
if x != nil {
return x.EventTimestamp
}
return nil
}
func (x *WorkflowEvent) GetEventPayload() string {
if x != nil {
return x.EventPayload
}
return ""
}
var File_dispatcher_proto protoreflect.FileDescriptor
var file_dispatcher_proto_rawDesc = []byte{
@@ -974,57 +1218,106 @@ var file_dispatcher_proto_rawDesc = []byte{
0x1a, 0x0a, 0x08, 0x74, 0x65, 0x6e, 0x61, 0x6e, 0x74, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28,
0x09, 0x52, 0x08, 0x74, 0x65, 0x6e, 0x61, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x77,
0x6f, 0x72, 0x6b, 0x65, 0x72, 0x49, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x77,
0x6f, 0x72, 0x6b, 0x65, 0x72, 0x49, 0x64, 0x2a, 0x4e, 0x0a, 0x0a, 0x41, 0x63, 0x74, 0x69, 0x6f,
0x6e, 0x54, 0x79, 0x70, 0x65, 0x12, 0x12, 0x0a, 0x0e, 0x53, 0x54, 0x41, 0x52, 0x54, 0x5f, 0x53,
0x54, 0x45, 0x50, 0x5f, 0x52, 0x55, 0x4e, 0x10, 0x00, 0x12, 0x13, 0x0a, 0x0f, 0x43, 0x41, 0x4e,
0x43, 0x45, 0x4c, 0x5f, 0x53, 0x54, 0x45, 0x50, 0x5f, 0x52, 0x55, 0x4e, 0x10, 0x01, 0x12, 0x17,
0x0a, 0x13, 0x53, 0x54, 0x41, 0x52, 0x54, 0x5f, 0x47, 0x45, 0x54, 0x5f, 0x47, 0x52, 0x4f, 0x55,
0x50, 0x5f, 0x4b, 0x45, 0x59, 0x10, 0x02, 0x2a, 0xa2, 0x01, 0x0a, 0x17, 0x47, 0x72, 0x6f, 0x75,
0x70, 0x4b, 0x65, 0x79, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x54,
0x79, 0x70, 0x65, 0x12, 0x20, 0x0a, 0x1c, 0x47, 0x52, 0x4f, 0x55, 0x50, 0x5f, 0x4b, 0x45, 0x59,
0x5f, 0x45, 0x56, 0x45, 0x4e, 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x4b, 0x4e,
0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x20, 0x0a, 0x1c, 0x47, 0x52, 0x4f, 0x55, 0x50, 0x5f, 0x4b,
0x45, 0x59, 0x5f, 0x45, 0x56, 0x45, 0x4e, 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x53, 0x54,
0x41, 0x52, 0x54, 0x45, 0x44, 0x10, 0x01, 0x12, 0x22, 0x0a, 0x1e, 0x47, 0x52, 0x4f, 0x55, 0x50,
0x5f, 0x4b, 0x45, 0x59, 0x5f, 0x45, 0x56, 0x45, 0x4e, 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f,
0x43, 0x4f, 0x4d, 0x50, 0x4c, 0x45, 0x54, 0x45, 0x44, 0x10, 0x02, 0x12, 0x1f, 0x0a, 0x1b, 0x47,
0x52, 0x4f, 0x55, 0x50, 0x5f, 0x4b, 0x45, 0x59, 0x5f, 0x45, 0x56, 0x45, 0x4e, 0x54, 0x5f, 0x54,
0x59, 0x50, 0x45, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, 0x10, 0x03, 0x2a, 0x8a, 0x01, 0x0a,
0x13, 0x53, 0x74, 0x65, 0x70, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x76, 0x65, 0x6e, 0x74,
0x54, 0x79, 0x70, 0x65, 0x12, 0x1b, 0x0a, 0x17, 0x53, 0x54, 0x45, 0x50, 0x5f, 0x45, 0x56, 0x45,
0x4e, 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10,
0x00, 0x12, 0x1b, 0x0a, 0x17, 0x53, 0x54, 0x45, 0x50, 0x5f, 0x45, 0x56, 0x45, 0x4e, 0x54, 0x5f,
0x54, 0x59, 0x50, 0x45, 0x5f, 0x53, 0x54, 0x41, 0x52, 0x54, 0x45, 0x44, 0x10, 0x01, 0x12, 0x1d,
0x0a, 0x19, 0x53, 0x54, 0x45, 0x50, 0x5f, 0x45, 0x56, 0x45, 0x4e, 0x54, 0x5f, 0x54, 0x59, 0x50,
0x45, 0x5f, 0x43, 0x4f, 0x4d, 0x50, 0x4c, 0x45, 0x54, 0x45, 0x44, 0x10, 0x02, 0x12, 0x1a, 0x0a,
0x16, 0x53, 0x54, 0x45, 0x50, 0x5f, 0x45, 0x56, 0x45, 0x4e, 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45,
0x5f, 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, 0x10, 0x03, 0x32, 0xd2, 0x02, 0x0a, 0x0a, 0x44, 0x69,
0x73, 0x70, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x12, 0x3d, 0x0a, 0x08, 0x52, 0x65, 0x67, 0x69,
0x73, 0x74, 0x65, 0x72, 0x12, 0x16, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x52, 0x65, 0x67,
0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x57,
0x6f, 0x72, 0x6b, 0x65, 0x72, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x73,
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x33, 0x0a, 0x06, 0x4c, 0x69, 0x73, 0x74, 0x65,
0x6e, 0x12, 0x14, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x4c, 0x69, 0x73, 0x74, 0x65, 0x6e,
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0f, 0x2e, 0x41, 0x73, 0x73, 0x69, 0x67, 0x6e,
0x65, 0x64, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x00, 0x30, 0x01, 0x12, 0x3f, 0x0a, 0x13,
0x53, 0x65, 0x6e, 0x64, 0x53, 0x74, 0x65, 0x70, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x76,
0x65, 0x6e, 0x74, 0x12, 0x10, 0x2e, 0x53, 0x74, 0x65, 0x70, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e,
0x45, 0x76, 0x65, 0x6e, 0x74, 0x1a, 0x14, 0x2e, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x76,
0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x47, 0x0a,
0x17, 0x53, 0x65, 0x6e, 0x64, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x4b, 0x65, 0x79, 0x41, 0x63, 0x74,
0x69, 0x6f, 0x6e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x14, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70,
0x4b, 0x65, 0x79, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x1a, 0x14,
0x2e, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70,
0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x46, 0x0a, 0x0b, 0x55, 0x6e, 0x73, 0x75, 0x62, 0x73,
0x63, 0x72, 0x69, 0x62, 0x65, 0x12, 0x19, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x55, 0x6e,
0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
0x1a, 0x1a, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x55, 0x6e, 0x73, 0x75, 0x62, 0x73, 0x63,
0x72, 0x69, 0x62, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x47,
0x5a, 0x45, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61, 0x74,
0x63, 0x68, 0x65, 0x74, 0x2d, 0x64, 0x65, 0x76, 0x2f, 0x68, 0x61, 0x74, 0x63, 0x68, 0x65, 0x74,
0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63,
0x65, 0x73, 0x2f, 0x64, 0x69, 0x73, 0x70, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x2f, 0x63, 0x6f,
0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
0x6f, 0x72, 0x6b, 0x65, 0x72, 0x49, 0x64, 0x22, 0x48, 0x0a, 0x20, 0x53, 0x75, 0x62, 0x73, 0x63,
0x72, 0x69, 0x62, 0x65, 0x54, 0x6f, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x45, 0x76,
0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x24, 0x0a, 0x0d, 0x77,
0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x52, 0x75, 0x6e, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01,
0x28, 0x09, 0x52, 0x0d, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x52, 0x75, 0x6e, 0x49,
0x64, 0x22, 0xa2, 0x02, 0x0a, 0x0d, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x45, 0x76,
0x65, 0x6e, 0x74, 0x12, 0x24, 0x0a, 0x0d, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x52,
0x75, 0x6e, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x77, 0x6f, 0x72, 0x6b,
0x66, 0x6c, 0x6f, 0x77, 0x52, 0x75, 0x6e, 0x49, 0x64, 0x12, 0x31, 0x0a, 0x0c, 0x72, 0x65, 0x73,
0x6f, 0x75, 0x72, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32,
0x0d, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x52, 0x0c,
0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x30, 0x0a, 0x09,
0x65, 0x76, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32,
0x12, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x54,
0x79, 0x70, 0x65, 0x52, 0x09, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1e,
0x0a, 0x0a, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x18, 0x04, 0x20, 0x01,
0x28, 0x09, 0x52, 0x0a, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x12, 0x42,
0x0a, 0x0e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70,
0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61,
0x6d, 0x70, 0x52, 0x0e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61,
0x6d, 0x70, 0x12, 0x22, 0x0a, 0x0c, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x50, 0x61, 0x79, 0x6c, 0x6f,
0x61, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x50,
0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x2a, 0x4e, 0x0a, 0x0a, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e,
0x54, 0x79, 0x70, 0x65, 0x12, 0x12, 0x0a, 0x0e, 0x53, 0x54, 0x41, 0x52, 0x54, 0x5f, 0x53, 0x54,
0x45, 0x50, 0x5f, 0x52, 0x55, 0x4e, 0x10, 0x00, 0x12, 0x13, 0x0a, 0x0f, 0x43, 0x41, 0x4e, 0x43,
0x45, 0x4c, 0x5f, 0x53, 0x54, 0x45, 0x50, 0x5f, 0x52, 0x55, 0x4e, 0x10, 0x01, 0x12, 0x17, 0x0a,
0x13, 0x53, 0x54, 0x41, 0x52, 0x54, 0x5f, 0x47, 0x45, 0x54, 0x5f, 0x47, 0x52, 0x4f, 0x55, 0x50,
0x5f, 0x4b, 0x45, 0x59, 0x10, 0x02, 0x2a, 0xa2, 0x01, 0x0a, 0x17, 0x47, 0x72, 0x6f, 0x75, 0x70,
0x4b, 0x65, 0x79, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x54, 0x79,
0x70, 0x65, 0x12, 0x20, 0x0a, 0x1c, 0x47, 0x52, 0x4f, 0x55, 0x50, 0x5f, 0x4b, 0x45, 0x59, 0x5f,
0x45, 0x56, 0x45, 0x4e, 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f,
0x57, 0x4e, 0x10, 0x00, 0x12, 0x20, 0x0a, 0x1c, 0x47, 0x52, 0x4f, 0x55, 0x50, 0x5f, 0x4b, 0x45,
0x59, 0x5f, 0x45, 0x56, 0x45, 0x4e, 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x53, 0x54, 0x41,
0x52, 0x54, 0x45, 0x44, 0x10, 0x01, 0x12, 0x22, 0x0a, 0x1e, 0x47, 0x52, 0x4f, 0x55, 0x50, 0x5f,
0x4b, 0x45, 0x59, 0x5f, 0x45, 0x56, 0x45, 0x4e, 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x43,
0x4f, 0x4d, 0x50, 0x4c, 0x45, 0x54, 0x45, 0x44, 0x10, 0x02, 0x12, 0x1f, 0x0a, 0x1b, 0x47, 0x52,
0x4f, 0x55, 0x50, 0x5f, 0x4b, 0x45, 0x59, 0x5f, 0x45, 0x56, 0x45, 0x4e, 0x54, 0x5f, 0x54, 0x59,
0x50, 0x45, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, 0x10, 0x03, 0x2a, 0x8a, 0x01, 0x0a, 0x13,
0x53, 0x74, 0x65, 0x70, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x54,
0x79, 0x70, 0x65, 0x12, 0x1b, 0x0a, 0x17, 0x53, 0x54, 0x45, 0x50, 0x5f, 0x45, 0x56, 0x45, 0x4e,
0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00,
0x12, 0x1b, 0x0a, 0x17, 0x53, 0x54, 0x45, 0x50, 0x5f, 0x45, 0x56, 0x45, 0x4e, 0x54, 0x5f, 0x54,
0x59, 0x50, 0x45, 0x5f, 0x53, 0x54, 0x41, 0x52, 0x54, 0x45, 0x44, 0x10, 0x01, 0x12, 0x1d, 0x0a,
0x19, 0x53, 0x54, 0x45, 0x50, 0x5f, 0x45, 0x56, 0x45, 0x4e, 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45,
0x5f, 0x43, 0x4f, 0x4d, 0x50, 0x4c, 0x45, 0x54, 0x45, 0x44, 0x10, 0x02, 0x12, 0x1a, 0x0a, 0x16,
0x53, 0x54, 0x45, 0x50, 0x5f, 0x45, 0x56, 0x45, 0x4e, 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f,
0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, 0x10, 0x03, 0x2a, 0x65, 0x0a, 0x0c, 0x52, 0x65, 0x73, 0x6f,
0x75, 0x72, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x19, 0x0a, 0x15, 0x52, 0x45, 0x53, 0x4f,
0x55, 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57,
0x4e, 0x10, 0x00, 0x12, 0x1a, 0x0a, 0x16, 0x52, 0x45, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f,
0x54, 0x59, 0x50, 0x45, 0x5f, 0x53, 0x54, 0x45, 0x50, 0x5f, 0x52, 0x55, 0x4e, 0x10, 0x01, 0x12,
0x1e, 0x0a, 0x1a, 0x52, 0x45, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45,
0x5f, 0x57, 0x4f, 0x52, 0x4b, 0x46, 0x4c, 0x4f, 0x57, 0x5f, 0x52, 0x55, 0x4e, 0x10, 0x02, 0x2a,
0xde, 0x01, 0x0a, 0x11, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x45, 0x76, 0x65, 0x6e,
0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1f, 0x0a, 0x1b, 0x52, 0x45, 0x53, 0x4f, 0x55, 0x52, 0x43,
0x45, 0x5f, 0x45, 0x56, 0x45, 0x4e, 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x4b,
0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x1f, 0x0a, 0x1b, 0x52, 0x45, 0x53, 0x4f, 0x55, 0x52,
0x43, 0x45, 0x5f, 0x45, 0x56, 0x45, 0x4e, 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x53, 0x54,
0x41, 0x52, 0x54, 0x45, 0x44, 0x10, 0x01, 0x12, 0x21, 0x0a, 0x1d, 0x52, 0x45, 0x53, 0x4f, 0x55,
0x52, 0x43, 0x45, 0x5f, 0x45, 0x56, 0x45, 0x4e, 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x43,
0x4f, 0x4d, 0x50, 0x4c, 0x45, 0x54, 0x45, 0x44, 0x10, 0x02, 0x12, 0x1e, 0x0a, 0x1a, 0x52, 0x45,
0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x45, 0x56, 0x45, 0x4e, 0x54, 0x5f, 0x54, 0x59, 0x50,
0x45, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, 0x10, 0x03, 0x12, 0x21, 0x0a, 0x1d, 0x52, 0x45,
0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x45, 0x56, 0x45, 0x4e, 0x54, 0x5f, 0x54, 0x59, 0x50,
0x45, 0x5f, 0x43, 0x41, 0x4e, 0x43, 0x45, 0x4c, 0x4c, 0x45, 0x44, 0x10, 0x04, 0x12, 0x21, 0x0a,
0x1d, 0x52, 0x45, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x45, 0x56, 0x45, 0x4e, 0x54, 0x5f,
0x54, 0x59, 0x50, 0x45, 0x5f, 0x54, 0x49, 0x4d, 0x45, 0x44, 0x5f, 0x4f, 0x55, 0x54, 0x10, 0x05,
0x32, 0xa6, 0x03, 0x0a, 0x0a, 0x44, 0x69, 0x73, 0x70, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x12,
0x3d, 0x0a, 0x08, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x12, 0x16, 0x2e, 0x57, 0x6f,
0x72, 0x6b, 0x65, 0x72, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75,
0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x52, 0x65, 0x67, 0x69,
0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x33,
0x0a, 0x06, 0x4c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x12, 0x14, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x65,
0x72, 0x4c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0f,
0x2e, 0x41, 0x73, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x22,
0x00, 0x30, 0x01, 0x12, 0x52, 0x0a, 0x19, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65,
0x54, 0x6f, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73,
0x12, 0x21, 0x2e, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x54, 0x6f, 0x57, 0x6f,
0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75,
0x65, 0x73, 0x74, 0x1a, 0x0e, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x45, 0x76,
0x65, 0x6e, 0x74, 0x22, 0x00, 0x30, 0x01, 0x12, 0x3f, 0x0a, 0x13, 0x53, 0x65, 0x6e, 0x64, 0x53,
0x74, 0x65, 0x70, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x10,
0x2e, 0x53, 0x74, 0x65, 0x70, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x76, 0x65, 0x6e, 0x74,
0x1a, 0x14, 0x2e, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x65,
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x47, 0x0a, 0x17, 0x53, 0x65, 0x6e, 0x64,
0x47, 0x72, 0x6f, 0x75, 0x70, 0x4b, 0x65, 0x79, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x76,
0x65, 0x6e, 0x74, 0x12, 0x14, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x4b, 0x65, 0x79, 0x41, 0x63,
0x74, 0x69, 0x6f, 0x6e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x1a, 0x14, 0x2e, 0x41, 0x63, 0x74, 0x69,
0x6f, 0x6e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22,
0x00, 0x12, 0x46, 0x0a, 0x0b, 0x55, 0x6e, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65,
0x12, 0x19, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x55, 0x6e, 0x73, 0x75, 0x62, 0x73, 0x63,
0x72, 0x69, 0x62, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x57, 0x6f,
0x72, 0x6b, 0x65, 0x72, 0x55, 0x6e, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x52,
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x47, 0x5a, 0x45, 0x67, 0x69, 0x74,
0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61, 0x74, 0x63, 0x68, 0x65, 0x74, 0x2d,
0x64, 0x65, 0x76, 0x2f, 0x68, 0x61, 0x74, 0x63, 0x68, 0x65, 0x74, 0x2f, 0x69, 0x6e, 0x74, 0x65,
0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2f, 0x64, 0x69,
0x73, 0x70, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63,
0x74, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
@@ -1039,44 +1332,53 @@ func file_dispatcher_proto_rawDescGZIP() []byte {
return file_dispatcher_proto_rawDescData
}
var file_dispatcher_proto_enumTypes = make([]protoimpl.EnumInfo, 3)
var file_dispatcher_proto_msgTypes = make([]protoimpl.MessageInfo, 9)
var file_dispatcher_proto_enumTypes = make([]protoimpl.EnumInfo, 5)
var file_dispatcher_proto_msgTypes = make([]protoimpl.MessageInfo, 11)
var file_dispatcher_proto_goTypes = []interface{}{
(ActionType)(0), // 0: ActionType
(GroupKeyActionEventType)(0), // 1: GroupKeyActionEventType
(StepActionEventType)(0), // 2: StepActionEventType
(*WorkerRegisterRequest)(nil), // 3: WorkerRegisterRequest
(*WorkerRegisterResponse)(nil), // 4: WorkerRegisterResponse
(*AssignedAction)(nil), // 5: AssignedAction
(*WorkerListenRequest)(nil), // 6: WorkerListenRequest
(*WorkerUnsubscribeRequest)(nil), // 7: WorkerUnsubscribeRequest
(*WorkerUnsubscribeResponse)(nil), // 8: WorkerUnsubscribeResponse
(*GroupKeyActionEvent)(nil), // 9: GroupKeyActionEvent
(*StepActionEvent)(nil), // 10: StepActionEvent
(*ActionEventResponse)(nil), // 11: ActionEventResponse
(*timestamppb.Timestamp)(nil), // 12: google.protobuf.Timestamp
(ActionType)(0), // 0: ActionType
(GroupKeyActionEventType)(0), // 1: GroupKeyActionEventType
(StepActionEventType)(0), // 2: StepActionEventType
(ResourceType)(0), // 3: ResourceType
(ResourceEventType)(0), // 4: ResourceEventType
(*WorkerRegisterRequest)(nil), // 5: WorkerRegisterRequest
(*WorkerRegisterResponse)(nil), // 6: WorkerRegisterResponse
(*AssignedAction)(nil), // 7: AssignedAction
(*WorkerListenRequest)(nil), // 8: WorkerListenRequest
(*WorkerUnsubscribeRequest)(nil), // 9: WorkerUnsubscribeRequest
(*WorkerUnsubscribeResponse)(nil), // 10: WorkerUnsubscribeResponse
(*GroupKeyActionEvent)(nil), // 11: GroupKeyActionEvent
(*StepActionEvent)(nil), // 12: StepActionEvent
(*ActionEventResponse)(nil), // 13: ActionEventResponse
(*SubscribeToWorkflowEventsRequest)(nil), // 14: SubscribeToWorkflowEventsRequest
(*WorkflowEvent)(nil), // 15: WorkflowEvent
(*timestamppb.Timestamp)(nil), // 16: google.protobuf.Timestamp
}
var file_dispatcher_proto_depIdxs = []int32{
0, // 0: AssignedAction.actionType:type_name -> ActionType
12, // 1: GroupKeyActionEvent.eventTimestamp:type_name -> google.protobuf.Timestamp
16, // 1: GroupKeyActionEvent.eventTimestamp:type_name -> google.protobuf.Timestamp
1, // 2: GroupKeyActionEvent.eventType:type_name -> GroupKeyActionEventType
12, // 3: StepActionEvent.eventTimestamp:type_name -> google.protobuf.Timestamp
16, // 3: StepActionEvent.eventTimestamp:type_name -> google.protobuf.Timestamp
2, // 4: StepActionEvent.eventType:type_name -> StepActionEventType
3, // 5: Dispatcher.Register:input_type -> WorkerRegisterRequest
6, // 6: Dispatcher.Listen:input_type -> WorkerListenRequest
10, // 7: Dispatcher.SendStepActionEvent:input_type -> StepActionEvent
9, // 8: Dispatcher.SendGroupKeyActionEvent:input_type -> GroupKeyActionEvent
7, // 9: Dispatcher.Unsubscribe:input_type -> WorkerUnsubscribeRequest
4, // 10: Dispatcher.Register:output_type -> WorkerRegisterResponse
5, // 11: Dispatcher.Listen:output_type -> AssignedAction
11, // 12: Dispatcher.SendStepActionEvent:output_type -> ActionEventResponse
11, // 13: Dispatcher.SendGroupKeyActionEvent:output_type -> ActionEventResponse
8, // 14: Dispatcher.Unsubscribe:output_type -> WorkerUnsubscribeResponse
10, // [10:15] is the sub-list for method output_type
5, // [5:10] is the sub-list for method input_type
5, // [5:5] is the sub-list for extension type_name
5, // [5:5] is the sub-list for extension extendee
0, // [0:5] is the sub-list for field type_name
3, // 5: WorkflowEvent.resourceType:type_name -> ResourceType
4, // 6: WorkflowEvent.eventType:type_name -> ResourceEventType
16, // 7: WorkflowEvent.eventTimestamp:type_name -> google.protobuf.Timestamp
5, // 8: Dispatcher.Register:input_type -> WorkerRegisterRequest
8, // 9: Dispatcher.Listen:input_type -> WorkerListenRequest
14, // 10: Dispatcher.SubscribeToWorkflowEvents:input_type -> SubscribeToWorkflowEventsRequest
12, // 11: Dispatcher.SendStepActionEvent:input_type -> StepActionEvent
11, // 12: Dispatcher.SendGroupKeyActionEvent:input_type -> GroupKeyActionEvent
9, // 13: Dispatcher.Unsubscribe:input_type -> WorkerUnsubscribeRequest
6, // 14: Dispatcher.Register:output_type -> WorkerRegisterResponse
7, // 15: Dispatcher.Listen:output_type -> AssignedAction
15, // 16: Dispatcher.SubscribeToWorkflowEvents:output_type -> WorkflowEvent
13, // 17: Dispatcher.SendStepActionEvent:output_type -> ActionEventResponse
13, // 18: Dispatcher.SendGroupKeyActionEvent:output_type -> ActionEventResponse
10, // 19: Dispatcher.Unsubscribe:output_type -> WorkerUnsubscribeResponse
14, // [14:20] is the sub-list for method output_type
8, // [8:14] is the sub-list for method input_type
8, // [8:8] is the sub-list for extension type_name
8, // [8:8] is the sub-list for extension extendee
0, // [0:8] is the sub-list for field type_name
}
func init() { file_dispatcher_proto_init() }
@@ -1193,14 +1495,38 @@ func file_dispatcher_proto_init() {
return nil
}
}
file_dispatcher_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*SubscribeToWorkflowEventsRequest); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_dispatcher_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*WorkflowEvent); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_dispatcher_proto_rawDesc,
NumEnums: 3,
NumMessages: 9,
NumEnums: 5,
NumMessages: 11,
NumExtensions: 0,
NumServices: 1,
},
@@ -24,6 +24,7 @@ const _ = grpc.SupportPackageIsVersion7
type DispatcherClient interface {
Register(ctx context.Context, in *WorkerRegisterRequest, opts ...grpc.CallOption) (*WorkerRegisterResponse, error)
Listen(ctx context.Context, in *WorkerListenRequest, opts ...grpc.CallOption) (Dispatcher_ListenClient, error)
SubscribeToWorkflowEvents(ctx context.Context, in *SubscribeToWorkflowEventsRequest, opts ...grpc.CallOption) (Dispatcher_SubscribeToWorkflowEventsClient, error)
SendStepActionEvent(ctx context.Context, in *StepActionEvent, opts ...grpc.CallOption) (*ActionEventResponse, error)
SendGroupKeyActionEvent(ctx context.Context, in *GroupKeyActionEvent, opts ...grpc.CallOption) (*ActionEventResponse, error)
Unsubscribe(ctx context.Context, in *WorkerUnsubscribeRequest, opts ...grpc.CallOption) (*WorkerUnsubscribeResponse, error)
@@ -78,6 +79,38 @@ func (x *dispatcherListenClient) Recv() (*AssignedAction, error) {
return m, nil
}
func (c *dispatcherClient) SubscribeToWorkflowEvents(ctx context.Context, in *SubscribeToWorkflowEventsRequest, opts ...grpc.CallOption) (Dispatcher_SubscribeToWorkflowEventsClient, error) {
stream, err := c.cc.NewStream(ctx, &Dispatcher_ServiceDesc.Streams[1], "/Dispatcher/SubscribeToWorkflowEvents", opts...)
if err != nil {
return nil, err
}
x := &dispatcherSubscribeToWorkflowEventsClient{stream}
if err := x.ClientStream.SendMsg(in); err != nil {
return nil, err
}
if err := x.ClientStream.CloseSend(); err != nil {
return nil, err
}
return x, nil
}
type Dispatcher_SubscribeToWorkflowEventsClient interface {
Recv() (*WorkflowEvent, error)
grpc.ClientStream
}
type dispatcherSubscribeToWorkflowEventsClient struct {
grpc.ClientStream
}
func (x *dispatcherSubscribeToWorkflowEventsClient) Recv() (*WorkflowEvent, error) {
m := new(WorkflowEvent)
if err := x.ClientStream.RecvMsg(m); err != nil {
return nil, err
}
return m, nil
}
func (c *dispatcherClient) SendStepActionEvent(ctx context.Context, in *StepActionEvent, opts ...grpc.CallOption) (*ActionEventResponse, error) {
out := new(ActionEventResponse)
err := c.cc.Invoke(ctx, "/Dispatcher/SendStepActionEvent", in, out, opts...)
@@ -111,6 +144,7 @@ func (c *dispatcherClient) Unsubscribe(ctx context.Context, in *WorkerUnsubscrib
type DispatcherServer interface {
Register(context.Context, *WorkerRegisterRequest) (*WorkerRegisterResponse, error)
Listen(*WorkerListenRequest, Dispatcher_ListenServer) error
SubscribeToWorkflowEvents(*SubscribeToWorkflowEventsRequest, Dispatcher_SubscribeToWorkflowEventsServer) error
SendStepActionEvent(context.Context, *StepActionEvent) (*ActionEventResponse, error)
SendGroupKeyActionEvent(context.Context, *GroupKeyActionEvent) (*ActionEventResponse, error)
Unsubscribe(context.Context, *WorkerUnsubscribeRequest) (*WorkerUnsubscribeResponse, error)
@@ -127,6 +161,9 @@ func (UnimplementedDispatcherServer) Register(context.Context, *WorkerRegisterRe
func (UnimplementedDispatcherServer) Listen(*WorkerListenRequest, Dispatcher_ListenServer) error {
return status.Errorf(codes.Unimplemented, "method Listen not implemented")
}
func (UnimplementedDispatcherServer) SubscribeToWorkflowEvents(*SubscribeToWorkflowEventsRequest, Dispatcher_SubscribeToWorkflowEventsServer) error {
return status.Errorf(codes.Unimplemented, "method SubscribeToWorkflowEvents not implemented")
}
func (UnimplementedDispatcherServer) SendStepActionEvent(context.Context, *StepActionEvent) (*ActionEventResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method SendStepActionEvent not implemented")
}
@@ -188,6 +225,27 @@ func (x *dispatcherListenServer) Send(m *AssignedAction) error {
return x.ServerStream.SendMsg(m)
}
func _Dispatcher_SubscribeToWorkflowEvents_Handler(srv interface{}, stream grpc.ServerStream) error {
m := new(SubscribeToWorkflowEventsRequest)
if err := stream.RecvMsg(m); err != nil {
return err
}
return srv.(DispatcherServer).SubscribeToWorkflowEvents(m, &dispatcherSubscribeToWorkflowEventsServer{stream})
}
type Dispatcher_SubscribeToWorkflowEventsServer interface {
Send(*WorkflowEvent) error
grpc.ServerStream
}
type dispatcherSubscribeToWorkflowEventsServer struct {
grpc.ServerStream
}
func (x *dispatcherSubscribeToWorkflowEventsServer) Send(m *WorkflowEvent) error {
return x.ServerStream.SendMsg(m)
}
func _Dispatcher_SendStepActionEvent_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(StepActionEvent)
if err := dec(in); err != nil {
@@ -272,6 +330,11 @@ var Dispatcher_ServiceDesc = grpc.ServiceDesc{
Handler: _Dispatcher_Listen_Handler,
ServerStreams: true,
},
{
StreamName: "SubscribeToWorkflowEvents",
Handler: _Dispatcher_SubscribeToWorkflowEvents_Handler,
ServerStreams: true,
},
},
Metadata: "dispatcher.proto",
}
+1 -1
View File
@@ -195,7 +195,7 @@ func (d *DispatcherImpl) handleTask(ctx context.Context, task *taskqueue.Task) e
return d.handleStepRunCancelled(ctx, task)
}
return fmt.Errorf("unknown task: %s in queue %s", task.ID, string(task.Queue))
return fmt.Errorf("unknown task: %s", task.ID)
}
func (d *DispatcherImpl) handleGroupKeyActionAssignedTask(ctx context.Context, task *taskqueue.Task) error {
+103 -6
View File
@@ -276,6 +276,56 @@ func (s *DispatcherImpl) Listen(request *contracts.WorkerListenRequest, stream c
}
}
// SubscribeToWorkflowEvents registers workflow events with the dispatcher
func (s *DispatcherImpl) SubscribeToWorkflowEvents(request *contracts.SubscribeToWorkflowEventsRequest, stream contracts.Dispatcher_SubscribeToWorkflowEventsServer) error {
tenant := stream.Context().Value("tenant").(*db.TenantModel)
s.l.Debug().Msgf("Received subscribe request for workflow: %s", request.WorkflowRunId)
q, err := taskqueue.TenantEventConsumerQueue(tenant.ID)
if err != nil {
return err
}
ctx := stream.Context()
// subscribe to the task queue for the tenant
taskChan, err := s.tq.Subscribe(ctx, q)
if err != nil {
return err
}
for {
select {
case <-ctx.Done():
// drain the existing connections
return nil
case task := <-taskChan:
go func(task *taskqueue.Task) {
e, err := s.tenantTaskToWorkflowEvent(task, tenant.ID, request.WorkflowRunId)
if err != nil {
s.l.Error().Err(err).Msgf("could not convert task to workflow event")
return
} else if e == nil {
return
}
fmt.Println("<><><> SENDING TASK!!", e)
// send the task to the client
err = stream.Send(e)
if err != nil {
s.l.Error().Err(err).Msgf("could not send workflow event to client")
}
}(task)
}
}
}
func (s *DispatcherImpl) SendStepActionEvent(ctx context.Context, request *contracts.StepActionEvent) (*contracts.ActionEventResponse, error) {
switch request.EventType {
case contracts.StepActionEventType_STEP_EVENT_TYPE_STARTED:
@@ -339,7 +389,6 @@ func (s *DispatcherImpl) handleStepRunStarted(ctx context.Context, request *cont
// send the event to the jobs queue
err := s.tq.AddTask(ctx, taskqueue.JOB_PROCESSING_QUEUE, &taskqueue.Task{
ID: "step-run-started",
Queue: taskqueue.JOB_PROCESSING_QUEUE,
Payload: payload,
Metadata: metadata,
})
@@ -374,7 +423,6 @@ func (s *DispatcherImpl) handleStepRunCompleted(ctx context.Context, request *co
// send the event to the jobs queue
err := s.tq.AddTask(ctx, taskqueue.JOB_PROCESSING_QUEUE, &taskqueue.Task{
ID: "step-run-finished",
Queue: taskqueue.JOB_PROCESSING_QUEUE,
Payload: payload,
Metadata: metadata,
})
@@ -409,7 +457,6 @@ func (s *DispatcherImpl) handleStepRunFailed(ctx context.Context, request *contr
// send the event to the jobs queue
err := s.tq.AddTask(ctx, taskqueue.JOB_PROCESSING_QUEUE, &taskqueue.Task{
ID: "step-run-failed",
Queue: taskqueue.JOB_PROCESSING_QUEUE,
Payload: payload,
Metadata: metadata,
})
@@ -443,7 +490,6 @@ func (s *DispatcherImpl) handleGetGroupKeyRunStarted(ctx context.Context, reques
// send the event to the jobs queue
err := s.tq.AddTask(ctx, taskqueue.WORKFLOW_PROCESSING_QUEUE, &taskqueue.Task{
ID: "get-group-key-run-started",
Queue: taskqueue.WORKFLOW_PROCESSING_QUEUE,
Payload: payload,
Metadata: metadata,
})
@@ -478,7 +524,6 @@ func (s *DispatcherImpl) handleGetGroupKeyRunCompleted(ctx context.Context, requ
// send the event to the jobs queue
err := s.tq.AddTask(ctx, taskqueue.WORKFLOW_PROCESSING_QUEUE, &taskqueue.Task{
ID: "get-group-key-run-finished",
Queue: taskqueue.WORKFLOW_PROCESSING_QUEUE,
Payload: payload,
Metadata: metadata,
})
@@ -513,7 +558,6 @@ func (s *DispatcherImpl) handleGetGroupKeyRunFailed(ctx context.Context, request
// send the event to the jobs queue
err := s.tq.AddTask(ctx, taskqueue.WORKFLOW_PROCESSING_QUEUE, &taskqueue.Task{
ID: "get-group-key-run-failed",
Queue: taskqueue.WORKFLOW_PROCESSING_QUEUE,
Payload: payload,
Metadata: metadata,
})
@@ -527,3 +571,56 @@ func (s *DispatcherImpl) handleGetGroupKeyRunFailed(ctx context.Context, request
WorkerId: request.WorkerId,
}, nil
}
func (s *DispatcherImpl) tenantTaskToWorkflowEvent(task *taskqueue.Task, tenantId, workflowRunId string) (*contracts.WorkflowEvent, error) {
// TODO: eventually process workflows as well, this is just steps
workflowEvent := &contracts.WorkflowEvent{
ResourceType: contracts.ResourceType_RESOURCE_TYPE_STEP_RUN,
}
var stepRunId string
switch task.ID {
case "step-run-started":
stepRunId = task.Payload["step_run_id"].(string)
workflowEvent.ResourceId = stepRunId
workflowEvent.EventType = contracts.ResourceEventType_RESOURCE_EVENT_TYPE_STARTED
case "step-run-finished":
stepRunId = task.Payload["step_run_id"].(string)
workflowEvent.ResourceId = stepRunId
workflowEvent.EventType = contracts.ResourceEventType_RESOURCE_EVENT_TYPE_COMPLETED
workflowEvent.EventPayload = task.Payload["step_output_data"].(string)
case "step-run-failed":
stepRunId = task.Payload["step_run_id"].(string)
workflowEvent.ResourceId = stepRunId
workflowEvent.EventType = contracts.ResourceEventType_RESOURCE_EVENT_TYPE_FAILED
workflowEvent.EventPayload = task.Payload["error"].(string)
case "step-run-cancelled":
stepRunId = task.Payload["step_run_id"].(string)
workflowEvent.ResourceId = stepRunId
workflowEvent.EventType = contracts.ResourceEventType_RESOURCE_EVENT_TYPE_CANCELLED
case "step-run-timed-out":
stepRunId = task.Payload["step_run_id"].(string)
workflowEvent.ResourceId = stepRunId
workflowEvent.EventType = contracts.ResourceEventType_RESOURCE_EVENT_TYPE_TIMED_OUT
}
if stepRunId == "" {
// expected because not all tasks have step run ids
return nil, nil
}
// determine if this step run matches the workflow run id
stepRun, err := s.repo.StepRun().GetStepRunById(tenantId, stepRunId)
if err != nil {
return nil, err
}
if stepRun.JobRun().WorkflowRunID != workflowRunId {
// this is an expected error, so we don't return it
return nil, nil
}
return workflowEvent, nil
}
-3
View File
@@ -70,7 +70,6 @@ func tickerRemoved(tickerId string) *taskqueue.Task {
return &taskqueue.Task{
ID: "ticker-removed",
Queue: taskqueue.JOB_PROCESSING_QUEUE,
Payload: payload,
Metadata: metadata,
}
@@ -161,7 +160,6 @@ func cronScheduleTask(tickerId string, cronTriggerRef *db.WorkflowTriggerCronRef
return &taskqueue.Task{
ID: "schedule-cron",
Queue: taskqueue.QueueTypeFromTickerID(tickerId),
Payload: payload,
Metadata: metadata,
}, nil
@@ -180,7 +178,6 @@ func workflowScheduleTask(tickerId string, workflowTriggerRef *db.WorkflowTrigge
return &taskqueue.Task{
ID: "schedule-workflow",
Queue: taskqueue.QueueTypeFromTickerID(tickerId),
Payload: payload,
Metadata: metadata,
}, nil
-1
View File
@@ -150,7 +150,6 @@ func eventToTask(e *db.EventModel) *taskqueue.Task {
return &taskqueue.Task{
ID: "event",
Queue: taskqueue.EVENT_PROCESSING_QUEUE,
Payload: payload,
Metadata: metadata,
}
@@ -35,7 +35,6 @@ func TenantToGroupKeyActionRequeueTask(tenant db.TenantModel) *taskqueue.Task {
return &taskqueue.Task{
ID: "group-key-action-requeue-ticker",
Queue: taskqueue.WORKFLOW_PROCESSING_QUEUE,
Payload: payload,
Metadata: metadata,
}
@@ -32,7 +32,6 @@ func JobRunQueuedToTask(job *db.JobModel, jobRun *db.JobRunModel) *taskqueue.Tas
return &taskqueue.Task{
ID: "job-run-queued",
Queue: taskqueue.JOB_PROCESSING_QUEUE,
Payload: payload,
Metadata: metadata,
}
@@ -108,7 +108,6 @@ func TenantToStepRunRequeueTask(tenant db.TenantModel) *taskqueue.Task {
return &taskqueue.Task{
ID: "step-run-requeue-ticker",
Queue: taskqueue.JOB_PROCESSING_QUEUE,
Payload: payload,
Metadata: metadata,
}
@@ -131,7 +130,6 @@ func StepRunQueuedToTask(job *db.JobModel, stepRun *db.StepRunModel) *taskqueue.
return &taskqueue.Task{
ID: "step-run-queued",
Queue: taskqueue.JOB_PROCESSING_QUEUE,
Payload: payload,
Metadata: metadata,
}
@@ -27,7 +27,6 @@ func WorkflowRunQueuedToTask(workflowRun *db.WorkflowRunModel) *taskqueue.Task {
return &taskqueue.Task{
ID: "workflow-run-queued",
Queue: taskqueue.WORKFLOW_PROCESSING_QUEUE,
Payload: payload,
Metadata: metadata,
}
@@ -135,7 +135,6 @@ func taskGetGroupKeyRunTimedOut(tenantId, workflowRunId, getGroupKeyRunId string
return &taskqueue.Task{
ID: "get-group-key-run-timed-out",
Queue: taskqueue.WORKFLOW_PROCESSING_QUEUE,
Payload: payload,
Metadata: metadata,
}
@@ -134,7 +134,6 @@ func taskJobRunTimedOut(tenantId, jobRunId string) *taskqueue.Task {
return &taskqueue.Task{
ID: "job-run-timed-out",
Queue: taskqueue.JOB_PROCESSING_QUEUE,
Payload: payload,
Metadata: metadata,
}
@@ -135,7 +135,6 @@ func taskStepRunTimedOut(tenantId, jobRunId, stepRunId string) *taskqueue.Task {
return &taskqueue.Task{
ID: "step-run-timed-out",
Queue: taskqueue.JOB_PROCESSING_QUEUE,
Payload: payload,
Metadata: metadata,
}
+1 -2
View File
@@ -232,7 +232,7 @@ func (t *TickerImpl) handleTask(ctx context.Context, task *taskqueue.Task) error
return t.handleCancelWorkflow(ctx, task)
}
return fmt.Errorf("unknown task: %s in queue %s", task.ID, string(task.Queue))
return fmt.Errorf("unknown task: %s", task.ID)
}
func (t *TickerImpl) runStepRunRequeue(ctx context.Context) func() {
@@ -317,7 +317,6 @@ func tickerRemoved(tickerId string) *taskqueue.Task {
return &taskqueue.Task{
ID: "ticker-removed",
Queue: taskqueue.JOB_PROCESSING_QUEUE,
Payload: payload,
Metadata: metadata,
}
+148 -42
View File
@@ -8,9 +8,11 @@ import (
"os"
"time"
lru "github.com/hashicorp/golang-lru/v2"
amqp "github.com/rabbitmq/amqp091-go"
"github.com/rs/zerolog"
"github.com/hatchet-dev/hatchet/internal/encryption"
"github.com/hatchet-dev/hatchet/internal/logger"
"github.com/hatchet-dev/hatchet/internal/taskqueue"
)
@@ -21,14 +23,23 @@ type session struct {
*amqp.Channel
}
type taskWithQueue struct {
*taskqueue.Task
q taskqueue.Queue `json:"-"`
}
// TaskQueueImpl implements TaskQueue interface using AMQP.
type TaskQueueImpl struct {
ctx context.Context
sessions chan chan session
tasks chan *taskqueue.Task
tasks chan *taskWithQueue
identity string
l *zerolog.Logger
// lru cache for tenant ids
tenantIdCache *lru.Cache[string, bool]
}
type TaskQueueImplOpt func(*TaskQueueImplOpts)
@@ -70,25 +81,40 @@ func New(ctx context.Context, fs ...TaskQueueImplOpt) *TaskQueueImpl {
opts.l = &newLogger
sessions := redial(ctx, opts.l, opts.url)
tasks := make(chan *taskqueue.Task)
tasks := make(chan *taskWithQueue)
// create a new lru cache for tenant ids
tenantIdCache, _ := lru.New[string, bool](2000) // nolint: errcheck - this only returns an error if the size is less than 0
t := &TaskQueueImpl{
ctx: ctx,
sessions: sessions,
tasks: tasks,
identity: identity(),
l: opts.l,
ctx: ctx,
sessions: sessions,
tasks: tasks,
identity: identity(),
l: opts.l,
tenantIdCache: tenantIdCache,
}
// init the queues in a blocking fashion
for session := range sessions {
sub := <-session
sub := <-<-sessions
if _, err := t.initQueue(sub, taskqueue.EVENT_PROCESSING_QUEUE); err != nil {
t.l.Debug().Msgf("error initializing queue: %v", err)
return nil
}
t.initQueue(sub, string(taskqueue.EVENT_PROCESSING_QUEUE))
t.initQueue(sub, string(taskqueue.JOB_PROCESSING_QUEUE))
t.initQueue(sub, string(taskqueue.WORKFLOW_PROCESSING_QUEUE))
t.initQueue(sub, string(taskqueue.SCHEDULING_QUEUE))
break
if _, err := t.initQueue(sub, taskqueue.JOB_PROCESSING_QUEUE); err != nil {
t.l.Debug().Msgf("error initializing queue: %v", err)
return nil
}
if _, err := t.initQueue(sub, taskqueue.WORKFLOW_PROCESSING_QUEUE); err != nil {
t.l.Debug().Msgf("error initializing queue: %v", err)
return nil
}
if _, err := t.initQueue(sub, taskqueue.SCHEDULING_QUEUE); err != nil {
t.l.Debug().Msgf("error initializing queue: %v", err)
return nil
}
// create publisher go func
@@ -100,37 +126,82 @@ func New(ctx context.Context, fs ...TaskQueueImplOpt) *TaskQueueImpl {
}
// AddTask adds a task to the queue.
func (t *TaskQueueImpl) AddTask(ctx context.Context, queue taskqueue.QueueType, task *taskqueue.Task) error {
t.tasks <- task
func (t *TaskQueueImpl) AddTask(ctx context.Context, q taskqueue.Queue, task *taskqueue.Task) error {
t.tasks <- &taskWithQueue{
Task: task,
q: q,
}
return nil
}
// Subscribe subscribes to the task queue.
func (t *TaskQueueImpl) Subscribe(ctx context.Context, queueType taskqueue.QueueType) (<-chan *taskqueue.Task, error) {
t.l.Debug().Msgf("subscribed to queue: %s", string(queueType))
// init the queues in a blocking fashion
for session := range t.sessions {
sub := <-session
t.initQueue(sub, string(queueType))
break
}
func (t *TaskQueueImpl) Subscribe(ctx context.Context, q taskqueue.Queue) (<-chan *taskqueue.Task, error) {
t.l.Debug().Msgf("subscribing to queue: %s", q.Name())
tasks := make(chan *taskqueue.Task)
go t.subscribe(ctx, t.identity, string(queueType), t.sessions, t.tasks, tasks)
go t.subscribe(ctx, t.identity, q, t.sessions, t.tasks, tasks)
return tasks, nil
}
func (t *TaskQueueImpl) initQueue(sub session, name string) {
// amqp.Table(map[string]interface{}{
// "x-dead-letter-exchange": name,
// }
func (t *TaskQueueImpl) RegisterTenant(ctx context.Context, tenantId string) error {
// create a new fanout exchange for the tenant
sub := <-<-t.sessions
if _, err := sub.QueueDeclare(name, true, false, false, false, nil); err != nil {
t.l.Error().Msgf("cannot declare queue: %q, %v", name, err)
return
t.l.Debug().Msgf("registering tenant exchange: %s", tenantId)
// create a fanout exchange for the tenant. each consumer of the fanout exchange will get notified
// with the tenant events.
err := sub.ExchangeDeclare(
tenantId,
"fanout",
true, // durable
false, // auto-deleted
false, // not internal, accepts publishings
false, // no-wait
nil, // arguments
)
if err != nil {
t.l.Error().Msgf("cannot declare exchange: %q, %v", tenantId, err)
return err
}
t.tenantIdCache.Add(tenantId, true)
return nil
}
func (t *TaskQueueImpl) initQueue(sub session, q taskqueue.Queue) (string, error) {
name := q.Name()
if q.FanoutExchangeKey() != "" {
suffix, err := encryption.GenerateRandomBytes(4)
if err != nil {
t.l.Error().Msgf("error generating random bytes: %v", err)
return "", err
}
name = fmt.Sprintf("%s-%s", q.Name(), suffix)
}
if _, err := sub.QueueDeclare(name, q.Durable(), q.AutoDeleted(), q.Exclusive(), false, nil); err != nil {
t.l.Error().Msgf("cannot declare queue: %q, %v", name, err)
return "", err
}
// if the queue has a subscriber key, bind it to the fanout exchange
if q.FanoutExchangeKey() != "" {
t.l.Debug().Msgf("binding queue: %s to exchange: %s", name, q.FanoutExchangeKey())
if err := sub.QueueBind(name, "", q.FanoutExchangeKey(), false, nil); err != nil {
t.l.Error().Msgf("cannot bind queue: %q, %v", name, err)
return "", err
}
}
return name, nil
}
func (t *TaskQueueImpl) publish() {
@@ -138,7 +209,7 @@ func (t *TaskQueueImpl) publish() {
pub := <-session
for task := range t.tasks {
go func(task *taskqueue.Task) {
go func(task *taskWithQueue) {
body, err := json.Marshal(task)
if err != nil {
@@ -149,9 +220,9 @@ func (t *TaskQueueImpl) publish() {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
t.l.Debug().Msgf("publishing task %s to queue %s", task.ID, string(task.Queue))
t.l.Debug().Msgf("publishing task %s to queue %s", task.ID, task.q.Name())
err = pub.PublishWithContext(ctx, "", string(task.Queue), false, false, amqp.Publishing{
err = pub.PublishWithContext(ctx, "", task.q.Name(), false, false, amqp.Publishing{
Body: body,
})
@@ -160,28 +231,63 @@ func (t *TaskQueueImpl) publish() {
t.l.Error().Msgf("error publishing task: %v", err)
return
}
// if this is a tenant task, publish to the tenant exchange
if task.TenantID() != "" {
// determine if the tenant exchange exists
if _, ok := t.tenantIdCache.Get(task.TenantID()); !ok {
// register the tenant exchange
err = t.RegisterTenant(ctx, task.TenantID())
if err != nil {
t.l.Error().Msgf("error registering tenant exchange: %v", err)
return
}
}
t.l.Debug().Msgf("publishing tenant task %s to exchange %s", task.ID, task.TenantID())
err = pub.PublishWithContext(ctx, task.TenantID(), "", false, false, amqp.Publishing{
Body: body,
})
if err != nil {
t.l.Error().Msgf("error publishing tenant task: %v", err)
return
}
}
t.l.Debug().Msgf("published task %s to queue %s", task.ID, task.q.Name())
}(task)
}
}
}
func (t *TaskQueueImpl) subscribe(ctx context.Context, subId, queue string, sessions chan chan session, messages chan *taskqueue.Task, tasks chan<- *taskqueue.Task) {
func (t *TaskQueueImpl) subscribe(ctx context.Context, subId string, q taskqueue.Queue, sessions chan chan session, messages chan *taskWithQueue, tasks chan<- *taskqueue.Task) {
sessionCount := 0
for session := range sessions {
sessionCount++
sub := <-session
deliveries, err := sub.Consume(queue, subId, false, false, false, false, nil)
// we initialize the queue here because exclusive queues are bound to the session/connection. however, it's not clear
// if the exclusive queue will be available to the next session.
queueName, err := t.initQueue(sub, q)
if err != nil {
t.l.Error().Msgf("cannot consume from: %q, %v", queue, err)
return
}
deliveries, err := sub.Consume(queueName, subId, false, q.Exclusive(), false, false, nil)
if err != nil {
t.l.Error().Msgf("cannot consume from: %s, %v", queueName, err)
return
}
for msg := range deliveries {
go func(msg amqp.Delivery) {
task := &taskqueue.Task{}
task := &taskWithQueue{}
if err := json.Unmarshal(msg.Body, task); err != nil {
t.l.Error().Msgf("error unmarshaling message: %v", err)
@@ -190,7 +296,7 @@ func (t *TaskQueueImpl) subscribe(ctx context.Context, subId, queue string, sess
t.l.Debug().Msgf("(session: %d) got task: %v", sessionCount, task.ID)
tasks <- task
tasks <- task.Task
if err := sub.Ack(msg.DeliveryTag, false); err != nil {
t.l.Error().Msgf("error acknowledging message: %v", err)
@@ -0,0 +1,85 @@
//go:build integration
package rabbitmq_test
import (
"context"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/hatchet-dev/hatchet/internal/taskqueue"
"github.com/hatchet-dev/hatchet/internal/taskqueue/rabbitmq"
)
func TestTaskQueueIntegration(t *testing.T) {
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
url := "amqp://user:password@localhost:5672/"
// Initialize the task queue implementation
tq := rabbitmq.New(ctx,
rabbitmq.WithURL(url),
)
require.NotNil(t, tq, "task queue implementation should not be nil")
// Test adding a task to a static queue
staticQueue := taskqueue.EVENT_PROCESSING_QUEUE
task := &taskqueue.Task{
ID: "test-task-id",
Payload: map[string]interface{}{"key": "value"},
Metadata: map[string]interface{}{"tenant_id": "test-tenant"},
Retries: 1,
RetryDelay: 5,
}
err := tq.AddTask(ctx, staticQueue, task)
assert.NoError(t, err, "adding task to static queue should not error")
// Test subscription to the static queue
taskChan, err := tq.Subscribe(ctx, staticQueue)
require.NoError(t, err, "subscribing to static queue should not error")
select {
case receivedTask := <-taskChan:
assert.Equal(t, task.ID, receivedTask.ID, "received task ID should match sent task ID")
case <-time.After(5 * time.Second):
t.Fatal("timed out waiting for task from static queue")
}
// Test tenant registration and queue creation
tenantId := "test-tenant"
err = tq.RegisterTenant(ctx, tenantId)
assert.NoError(t, err, "registering tenant should not error")
// Assuming there's a mechanism to retrieve a tenant-specific queue, e.g., by tenant ID
tenantQueue, err := taskqueue.TenantEventConsumerQueue(tenantId)
if err != nil {
t.Fatalf("error creating tenant-specific queue: %v", err)
}
// Test subscription to the tenant-specific queue
tenantTaskChan, err := tq.Subscribe(ctx, tenantQueue)
require.NoError(t, err, "subscribing to tenant-specific queue should not error")
// send task to tenant-specific queue after 1 second to give time for subscriber
go func() {
time.Sleep(1 * time.Second)
err = tq.AddTask(ctx, tenantQueue, task)
assert.NoError(t, err, "adding task to tenant-specific queue should not error")
}()
select {
case receivedTask := <-tenantTaskChan:
assert.Equal(t, task.ID, receivedTask.ID, "received tenant task ID should match sent task ID")
break
case <-time.After(5 * time.Second):
t.Fatal("timed out waiting for task from tenant-specific queue")
break
}
}
+115 -17
View File
@@ -4,31 +4,107 @@ import (
"context"
)
type QueueType string
type Queue interface {
// Name returns the name of the queue.
Name() string
const (
EVENT_PROCESSING_QUEUE QueueType = "event_processing_queue"
JOB_PROCESSING_QUEUE QueueType = "job_processing_queue"
WORKFLOW_PROCESSING_QUEUE QueueType = "workflow_processing_queue"
DISPATCHER_POOL_QUEUE QueueType = "dispatcher_pool_queue"
SCHEDULING_QUEUE QueueType = "scheduling_queue"
)
// Durable returns true if this queue should survive task queue restarts.
Durable() bool
func QueueTypeFromDispatcherID(d string) QueueType {
return QueueType(d)
// AutoDeleted returns true if this queue should be deleted when the last consumer unsubscribes.
AutoDeleted() bool
// Exclusive returns true if this queue should only be accessed by the current connection.
Exclusive() bool
// FanoutExchangeKey returns which exchange the queue should be subscribed to. This is only currently relevant
// to tenant pub/sub queues.
//
// In RabbitMQ terminology, the existence of a subscriber key means that the queue is bound to a fanout
// exchange, and a new random queue is generated for each connection when connections are retried.
FanoutExchangeKey() string
}
func QueueTypeFromTickerID(t string) QueueType {
return QueueType(t)
type staticQueue string
const (
EVENT_PROCESSING_QUEUE staticQueue = "event_processing_queue"
JOB_PROCESSING_QUEUE staticQueue = "job_processing_queue"
WORKFLOW_PROCESSING_QUEUE staticQueue = "workflow_processing_queue"
DISPATCHER_POOL_QUEUE staticQueue = "dispatcher_pool_queue"
SCHEDULING_QUEUE staticQueue = "scheduling_queue"
)
func (s staticQueue) Name() string {
return string(s)
}
func (s staticQueue) Durable() bool {
return true
}
func (s staticQueue) AutoDeleted() bool {
return false
}
func (s staticQueue) Exclusive() bool {
return false
}
func (s staticQueue) FanoutExchangeKey() string {
return ""
}
type consumerQueue string
func (s consumerQueue) Name() string {
return string(s)
}
func (n consumerQueue) Durable() bool {
return false
}
func (n consumerQueue) AutoDeleted() bool {
return true
}
func (n consumerQueue) Exclusive() bool {
return true
}
func (n consumerQueue) FanoutExchangeKey() string {
return ""
}
func QueueTypeFromDispatcherID(d string) consumerQueue {
return consumerQueue(d)
}
func QueueTypeFromTickerID(t string) consumerQueue {
return consumerQueue(t)
}
type fanoutQueue struct {
consumerQueue
}
// The fanout exchange key for a consumer is the name of the consumer queue.
func (f fanoutQueue) FanoutExchangeKey() string {
return f.consumerQueue.Name()
}
func TenantEventConsumerQueue(t string) (fanoutQueue, error) {
// generate a unique queue name for the tenant
return fanoutQueue{
consumerQueue: consumerQueue(t),
}, nil
}
type Task struct {
// ID is the ID of the task.
ID string `json:"id"`
// Queue is the queue of the task.
Queue QueueType `json:"queue"`
// Payload is the payload of the task.
Payload map[string]interface{} `json:"payload"`
@@ -42,10 +118,32 @@ type Task struct {
RetryDelay int `json:"retry_delay"`
}
func (t *Task) TenantID() string {
tenantId, exists := t.Metadata["tenant_id"]
if !exists {
return ""
}
tenantIdStr, ok := tenantId.(string)
if !ok {
return ""
}
return tenantIdStr
}
type TaskQueue interface {
// AddTask adds a task to the queue. Implementations should ensure that Start().
AddTask(ctx context.Context, queue QueueType, task *Task) error
AddTask(ctx context.Context, queue Queue, task *Task) error
// Subscribe subscribes to the task queue.
Subscribe(ctx context.Context, queueType QueueType) (<-chan *Task, error)
Subscribe(ctx context.Context, queueType Queue) (<-chan *Task, error)
// RegisterTenant registers a new pub/sub mechanism for a tenant. This should be called when a
// new tenant is created. If this is not called, implementors should ensure that there's a check
// on the first message to a tenant to ensure that the tenant is registered, and store the tenant
// in an LRU cache which lives in-memory.
RegisterTenant(ctx context.Context, tenantId string) error
}
+26 -7
View File
@@ -18,13 +18,14 @@ import (
type AdminClient interface {
PutWorkflow(workflow *types.Workflow, opts ...PutOptFunc) error
ScheduleWorkflow(workflowName string, opts ...ScheduleOptFunc) error
// RunWorkflow triggers a workflow run and returns the run id
RunWorkflow(workflowName string, input interface{}) (string, error)
}
type adminClientImpl struct {
client admincontracts.WorkflowServiceClient
tenantId string
l *zerolog.Logger
v validator.Validator
@@ -34,11 +35,10 @@ type adminClientImpl struct {
func newAdmin(conn *grpc.ClientConn, opts *sharedClientOpts) AdminClient {
return &adminClientImpl{
client: admincontracts.NewWorkflowServiceClient(conn),
tenantId: opts.tenantId,
l: opts.l,
v: opts.v,
ctx: opts.ctxLoader,
client: admincontracts.NewWorkflowServiceClient(conn),
l: opts.l,
v: opts.v,
ctx: opts.ctxLoader,
}
}
@@ -141,6 +141,25 @@ func (a *adminClientImpl) ScheduleWorkflow(workflowName string, fs ...ScheduleOp
return nil
}
func (a *adminClientImpl) RunWorkflow(workflowName string, input interface{}) (string, error) {
inputBytes, err := json.Marshal(input)
if err != nil {
return "", fmt.Errorf("could not marshal input: %w", err)
}
res, err := a.client.TriggerWorkflow(a.ctx.newContext(context.Background()), &admincontracts.TriggerWorkflowRequest{
Name: workflowName,
Input: string(inputBytes),
})
if err != nil {
return "", fmt.Errorf("could not trigger workflow: %w", err)
}
return res.WorkflowRunId, nil
}
func (a *adminClientImpl) getPutRequest(workflow *types.Workflow) (*admincontracts.PutWorkflowRequest, error) {
opts := &admincontracts.CreateWorkflowVersionOpts{
Name: workflow.Name,
+8
View File
@@ -18,6 +18,7 @@ type Client interface {
Admin() AdminClient
Dispatcher() DispatcherClient
Event() EventClient
Run() RunClient
}
type clientImpl struct {
@@ -26,6 +27,7 @@ type clientImpl struct {
admin AdminClient
dispatcher DispatcherClient
event EventClient
run RunClient
// the tenant id
tenantId string
@@ -147,6 +149,7 @@ func New(fs ...ClientOpt) (Client, error) {
admin := newAdmin(conn, shared)
dispatcher := newDispatcher(conn, shared)
event := newEvent(conn, shared)
run := newRun(conn, shared)
// if init workflows is set, then we need to initialize the workflows
if opts.initWorkflows {
@@ -161,6 +164,7 @@ func New(fs ...ClientOpt) (Client, error) {
l: opts.l,
admin: admin,
dispatcher: dispatcher,
run: run,
event: event,
v: opts.v,
}, nil
@@ -178,6 +182,10 @@ func (c *clientImpl) Event() EventClient {
return c.event
}
func (c *clientImpl) Run() RunClient {
return c.run
}
func initWorkflows(fl filesLoaderFunc, adminClient AdminClient) error {
files := fl()
+97
View File
@@ -0,0 +1,97 @@
package client
import (
"context"
"github.com/rs/zerolog"
"google.golang.org/grpc"
dispatchercontracts "github.com/hatchet-dev/hatchet/internal/services/dispatcher/contracts"
"github.com/hatchet-dev/hatchet/internal/validator"
)
type RunHandler func(event *StepRunEvent) error
type RunClient interface {
On(ctx context.Context, workflowRunId string, handler RunHandler) error
}
type StepRunEventType string
const (
StepRunEventTypeStarted StepRunEventType = "STEP_RUN_EVENT_TYPE_STARTED"
StepRunEventTypeCompleted StepRunEventType = "STEP_RUN_EVENT_TYPE_COMPLETED"
StepRunEventTypeFailed StepRunEventType = "STEP_RUN_EVENT_TYPE_FAILED"
StepRunEventTypeCancelled StepRunEventType = "STEP_RUN_EVENT_TYPE_CANCELLED"
StepRunEventTypeTimedOut StepRunEventType = "STEP_RUN_EVENT_TYPE_TIMED_OUT"
)
type StepRunEvent struct {
Type StepRunEventType
Payload []byte
}
type ClientEventListener interface {
OnStepRunEvent(ctx context.Context, event *StepRunEvent) error
// OnWorkflowRunEvent(ctx context.Context, event *WorkflowRunEvent) error
}
type runClientImpl struct {
client dispatchercontracts.DispatcherClient
l *zerolog.Logger
v validator.Validator
ctx *contextLoader
}
func newRun(conn *grpc.ClientConn, opts *sharedClientOpts) RunClient {
return &runClientImpl{
client: dispatchercontracts.NewDispatcherClient(conn),
l: opts.l,
v: opts.v,
ctx: opts.ctxLoader,
}
}
func (r *runClientImpl) On(ctx context.Context, workflowRunId string, handler RunHandler) error {
stream, err := r.client.SubscribeToWorkflowEvents(r.ctx.newContext(ctx), &dispatchercontracts.SubscribeToWorkflowEventsRequest{
WorkflowRunId: workflowRunId,
})
if err != nil {
return err
}
for {
event, err := stream.Recv()
if err != nil {
return err
}
var eventType StepRunEventType
switch event.EventType {
case dispatchercontracts.ResourceEventType_RESOURCE_EVENT_TYPE_STARTED:
eventType = StepRunEventTypeStarted
case dispatchercontracts.ResourceEventType_RESOURCE_EVENT_TYPE_COMPLETED:
eventType = StepRunEventTypeCompleted
case dispatchercontracts.ResourceEventType_RESOURCE_EVENT_TYPE_FAILED:
eventType = StepRunEventTypeFailed
case dispatchercontracts.ResourceEventType_RESOURCE_EVENT_TYPE_CANCELLED:
eventType = StepRunEventTypeCancelled
case dispatchercontracts.ResourceEventType_RESOURCE_EVENT_TYPE_TIMED_OUT:
eventType = StepRunEventTypeTimedOut
}
if err := handler(&StepRunEvent{
Type: eventType,
Payload: []byte(event.EventPayload),
}); err != nil {
return err
}
}
}
@@ -44,7 +44,8 @@ ADD COLUMN "id" UUID NOT NULL,
ADD CONSTRAINT "WorkflowRun_pkey" PRIMARY KEY ("id");
-- AlterTable
ALTER TABLE "WorkflowRunTriggeredBy" DROP COLUMN "parentId",
ALTER TABLE "WorkflowRunTriggeredBy" ADD COLUMN "input" JSONB,
DROP COLUMN "parentId",
ADD COLUMN "parentId" UUID NOT NULL;
-- CreateIndex
+3
View File
@@ -621,6 +621,9 @@ model WorkflowRunTriggeredBy {
parent WorkflowRun @relation(fields: [parentId], references: [id], onDelete: Cascade, onUpdate: Cascade)
parentId String @unique @db.Uuid
// the input if this was triggered manually
input Json?
// the parent event
event Event? @relation(fields: [eventId], references: [id])
eventId String? @db.Uuid