Skip to content

Commit

Permalink
feat: pauseable workflows (#879)
Browse files Browse the repository at this point in the history
* feat: pause workflow state

* feat: dont run paused workflows

* feat: skipped paused

* implement unpaused behavior for workflow runs

* fix: frontend

* fix: more frontend

* fix: imports

---------

Co-authored-by: Alexander Belanger <[email protected]>
  • Loading branch information
grutt and abelanger5 authored Sep 29, 2024
1 parent dd385c5 commit 7d7e43d
Show file tree
Hide file tree
Showing 38 changed files with 1,590 additions and 238 deletions.
2 changes: 2 additions & 0 deletions api-contracts/openapi/components/schemas/_index.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,8 @@ CancelEventRequest:
$ref: "./event.yaml#/CancelEventRequest"
Workflow:
$ref: "./workflow.yaml#/Workflow"
WorkflowUpdateRequest:
$ref: "./workflow.yaml#/WorkflowUpdateRequest"
WorkflowConcurrency:
$ref: "./workflow.yaml#/WorkflowConcurrency"
WorkflowVersionMeta:
Expand Down
10 changes: 10 additions & 0 deletions api-contracts/openapi/components/schemas/workflow.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ Workflow:
description:
type: string
description: The description of the workflow.
isPaused:
type: boolean
description: Whether the workflow is paused.
versions:
type: array
items:
Expand All @@ -27,6 +30,13 @@ Workflow:
- name
type: object

WorkflowUpdateRequest:
type: object
properties:
isPaused:
type: boolean
description: Whether the workflow is paused.

WorkflowTag:
type: object
properties:
Expand Down
43 changes: 43 additions & 0 deletions api-contracts/openapi/paths/workflow/workflow.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,49 @@ withWorkflow:
summary: Delete workflow
tags:
- Workflow
patch:
x-resources: ["tenant", "workflow"]
description: Update a workflow for a tenant
operationId: workflow:update
parameters:
- description: The workflow id
in: path
name: workflow
required: true
schema:
type: string
format: uuid
minLength: 36
maxLength: 36
requestBody:
content:
application/json:
schema:
$ref: "../../components/schemas/_index.yaml#/WorkflowUpdateRequest"
description: The input to update the workflow
required: true
responses:
"200":
content:
application/json:
schema:
$ref: "../../components/schemas/_index.yaml#/Workflow"
description: Successfully updated the workflow
"400":
content:
application/json:
schema:
$ref: "../../components/schemas/_index.yaml#/APIErrors"
description: A malformed or bad request
"403":
content:
application/json:
schema:
$ref: "../../components/schemas/_index.yaml#/APIErrors"
description: Forbidden
summary: Update workflow
tags:
- Workflow
workflowVersion:
get:
x-resources: ["tenant", "workflow"]
Expand Down
31 changes: 31 additions & 0 deletions api/v1/server/handlers/workflows/update.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package workflows

import (
"github.com/labstack/echo/v4"

"github.com/hatchet-dev/hatchet/api/v1/server/oas/gen"
"github.com/hatchet-dev/hatchet/api/v1/server/oas/transformers"
"github.com/hatchet-dev/hatchet/pkg/repository"
"github.com/hatchet-dev/hatchet/pkg/repository/prisma/db"
"github.com/hatchet-dev/hatchet/pkg/repository/prisma/dbsqlc"
"github.com/hatchet-dev/hatchet/pkg/repository/prisma/sqlchelpers"
)

func (t *WorkflowService) WorkflowUpdate(ctx echo.Context, request gen.WorkflowUpdateRequestObject) (gen.WorkflowUpdateResponseObject, error) {
tenant := ctx.Get("tenant").(*db.TenantModel)
workflow := ctx.Get("workflow").(*dbsqlc.GetWorkflowByIdRow)

opts := repository.UpdateWorkflowOpts{
IsPaused: request.Body.IsPaused,
}

updated, err := t.config.APIRepository.Workflow().UpdateWorkflow(ctx.Request().Context(), tenant.ID, sqlchelpers.UUIDToStr(workflow.Workflow.ID), &opts)

if err != nil {
return nil, err
}

resp := transformers.ToWorkflowFromSQLC(updated)

return gen.WorkflowUpdate200JSONResponse(*resp), nil
}
446 changes: 276 additions & 170 deletions api/v1/server/oas/gen/openapi.gen.go

Large diffs are not rendered by default.

7 changes: 5 additions & 2 deletions api/v1/server/oas/transformers/workflow.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ func ToWorkflow(
Name: workflow.Name,
}

res.IsPaused = &workflow.IsPaused.Bool

res.Description = &workflow.Description.String

if version != nil {
Expand All @@ -44,7 +46,7 @@ func ToWorkflowVersionMeta(version *dbsqlc.WorkflowVersion, workflow *dbsqlc.Wor
version.UpdatedAt.Time,
),
WorkflowId: sqlchelpers.UUIDToStr(version.WorkflowId),
Order: int32(version.Order),
Order: int32(version.Order), // nolint: gosec
Version: version.Version.String,
}

Expand Down Expand Up @@ -73,7 +75,7 @@ func ToWorkflowVersion(
version.UpdatedAt.Time,
),
// WorkflowId: sqlchelpers.UUIDToStr(version.WorkflowId),
Order: int32(version.Order),
Order: int32(version.Order), // nolint: gosec
Version: version.Version.String,
ScheduleTimeout: &version.ScheduleTimeout,
DefaultPriority: &version.DefaultPriority.Int32,
Expand Down Expand Up @@ -290,6 +292,7 @@ func ToWorkflowFromSQLC(row *dbsqlc.Workflow) *gen.Workflow {
Metadata: *toAPIMetadata(pgUUIDToStr(row.ID), row.CreatedAt.Time, row.UpdatedAt.Time),
Name: row.Name,
Description: &row.Description.String,
IsPaused: &row.IsPaused.Bool,
}

return res
Expand Down
Original file line number Diff line number Diff line change
@@ -1,25 +1,15 @@
// Inspired by react-hot-toast library
import * as React from 'react';

import type { ToastActionElement, ToastProps } from '@/components/ui/toast';

const TOAST_LIMIT = 1;
const TOAST_REMOVE_DELAY = 1000000;

// Add this type definition
export type ToastPosition =
| 'top-left'
| 'top-right'
| 'bottom-left'
| 'bottom-right';

// Modify the existing ToasterToast type
type ToasterToast = ToastProps & {
id: string;
title?: React.ReactNode;
description?: React.ReactNode;
action?: ToastActionElement;
position?: ToastPosition;
};

const actionTypes = {
Expand Down Expand Up @@ -144,10 +134,9 @@ function dispatch(action: Action) {
});
}

// Modify the Toast type
type Toast = Omit<ToasterToast, 'id'>;

function toast({ position = 'bottom-right', ...props }: Toast) {
function toast({ ...props }: Toast) {
const id = genId();

const update = (props: ToasterToast) =>
Expand All @@ -162,7 +151,6 @@ function toast({ position = 'bottom-right', ...props }: Toast) {
toast: {
...props,
id,
position,
open: true,
onOpenChange: (open) => {
if (!open) {
Expand Down
23 changes: 6 additions & 17 deletions frontend/app/src/components/ui/toast.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import * as React from 'react';
import { Cross2Icon } from '@radix-ui/react-icons';
import * as ToastPrimitives from '@radix-ui/react-toast';
import { cva, type VariantProps } from 'class-variance-authority';

import { cn } from '@/lib/utils';
import { ToastPosition } from './use-toast';

const ToastProvider = ToastPrimitives.Provider;

Expand All @@ -14,7 +14,7 @@ const ToastViewport = React.forwardRef<
<ToastPrimitives.Viewport
ref={ref}
className={cn(
'fixed z-[100] flex max-h-screen w-full flex-col-reverse p-4 sm:flex-col md:max-w-[420px]',
'fixed top-0 z-[100] flex max-h-screen w-full flex-col-reverse p-4 sm:bottom-0 sm:right-0 sm:top-auto sm:flex-col md:max-w-[420px]',
className,
)}
{...props}
Expand All @@ -27,7 +27,7 @@ const toastVariants = cva(
{
variants: {
variant: {
default: 'border bg-background text-foreground',
default: 'border-foreground bg-background text-foreground',
destructive:
'destructive group border-destructive bg-destructive text-destructive-foreground',
},
Expand All @@ -41,23 +41,12 @@ const toastVariants = cva(
const Toast = React.forwardRef<
React.ElementRef<typeof ToastPrimitives.Root>,
React.ComponentPropsWithoutRef<typeof ToastPrimitives.Root> &
VariantProps<typeof toastVariants> & {
position?: ToastPosition;
}
>(({ className, variant, position = 'bottom-right', ...props }, ref) => {
VariantProps<typeof toastVariants>
>(({ className, variant, ...props }, ref) => {
return (
<ToastPrimitives.Root
ref={ref}
className={cn(
toastVariants({ variant }),
{
'top-0 left-0': position === 'top-left',
'top-0 right-0': position === 'top-right',
'bottom-0 left-0': position === 'bottom-left',
'bottom-0 right-0': position === 'bottom-right',
},
className,
)}
className={cn(toastVariants({ variant }), className)}
{...props}
/>
);
Expand Down
2 changes: 1 addition & 1 deletion frontend/app/src/components/ui/toaster.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { useToast } from '@/components/hooks/use-toast';
import {
Toast,
ToastClose,
Expand All @@ -6,7 +7,6 @@ import {
ToastTitle,
ToastViewport,
} from '@/components/ui/toast';
import { useToast } from '@/components/ui/use-toast';

export function Toaster() {
const { toasts } = useToast();
Expand Down
Loading

0 comments on commit 7d7e43d

Please sign in to comment.