slackapi / deno-slack-sdk

SDK for building Run on Slack apps using Deno

Home Page:https://api.slack.com/automation

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

[QUERY] Is there a way to stop a workflow in an early step without throwing error to an admin via Slackbot?

spoike opened this issue · comments

Question

The main question is if it is allowed to NOT call client.function.completeError/Success in a ViewClosedHandler callback in order to stop a Slack workflow early?

Context

Normally a SlackFunction is completed successfully or fails. But what about stopping the workflow early? The use case in mind is handling a modal view that the user closes early. You can do the following:

Call functions.completeSuccess

export default SlackFunction(..., ...)
  .addViewClosedHandler("myview", () => ({ client, body }) {
    /* clean up stuff */
    
    return await client.functions.completeSuccess({
      function_execution_id: body.function_data.execution_id,
      outputs: {}
    })
  })

The drawback with this is that the rest of the workflow needs to handle undefined or null outputs, and add some kind of a short circuit logic for all other slack functions.

Call functions.completeError

export default SlackFunction(..., ...)
  .addViewClosedHandler("myview", () => ({ client, body }) {
    /* clean up stuff */
    
    return await client.functions.completeError({
      function_execution_id: body.function_data.execution_id,
      error: "User closed the dialog early"
    })
  })

The drawback with this approach is that whenever the user legitimately closes the modal window (e.g. they don't have the time to complete the modal inputs) then the admins are all pinged by SlackBot with this error.

Do nothing at all

export default SlackFunction(..., ...)
  .addViewClosedHandler("myview", () => ({ client, body }) {
    /* clean up stuff */

   console.log('user closed the modal view early');
   // do nothing
  })

The modal view closes, an entry in activity log is made (when console.log is used) and the workflow doesn't continue (which is desired effect). However this possibility is not documented anywhere and I'm not sure if this will create some memory leak on Slack's end. Is this an allowed way of exiting the workflow early?

Environment

Not really applicable but:

  • Paste the output of cat import_map.json | grep deno-slack
    "deno-slack-sdk/": "https://deno.land/x/deno_slack_sdk@2.5.0/",
    "deno-slack-api/": "https://deno.land/x/deno_slack_api@2.1.2/",
  • Paste the output of deno --version
deno 1.39.4 (release, x86_64-apple-darwin)
v8 12.0.267.8
typescript 5.3.3
  • Paste the output of sw_vers && uname -v on macOS/Linux or ver on Windows OS
ProductName:            macOS
ProductVersion:         14.2.1
BuildVersion:           23C71
Darwin Kernel Version 23.2.0: Wed Nov 15 21:54:10 PST 2023; root:xnu-10002.61.3~2/RELEASE_X86_64

Requirements

Please read the Contributing guidelines and Code of Conduct before creating this issue or pull request. By submitting, you are agreeing to those rules.

Cool beans 🤘

Hi, @spoike! Thanks so much for your query. 🙇

Since this isn't documented, I will check with the team internally to see if your proposed approach to "do nothing" is the standard for terminating a workflow early - will get back to you as soon as I have an update!

hi, @spoike!

After checking with the team, it seems like it's valid to end a workflow without reporting a success or error. There is not really much insights with regard to the memory leaks side as of right now, but your current approach seems like a valid pattern you can continue with! I'll be sure to update this if that changes.

I also surfaced this to our documentation team due to your suggestion of documenting it! I'll get back to you on any updates the team makes.

Thank you so much for submitting this question and feedback! 🙇

Thanks for the info!

I have a need for this exact thing. However, in my custom function I am not using a modal, and thus I do not have a closed/submission handler - it is just a custom function (step) that is added to a workflow.

Is there a workaround to do something similar where you don't have a closed/submission handler?

@mcsescott sure, just set completed: false in the return value of your custom function/step.

Under the hood, the deno-slack-runtime project, which powers both the slack run local experience as well as the deployed-to-Slack slack deploy experience, will run your function, and based on the returned object's error and completed properties, will either hit the functions.completeSuccess or functions.completeError method (code ref here).

As long as both error and completed on the output object returned by your custom step are falsy, then neither of the functions.complete* APIs will be hit. However, this means the workflow engine will not continue with the next step in the workflow after your function. Not sure if that is what you want or not... what's your use case, if you don't mind me being nosy?

Thanks, @filmaj .

I just tried returning completed: false and the workflow shows as "In progress", so it does appear to be working and will stall the workflow. I wonder if there is/will be a timeout where it will eventually spit out an error. Thinking about it, though, other workflows that are "in progress" don't really time out, so I guess we can live with that. :-) It's not like you give us an export capability from the activity log anyway. :-P

Use case: Trying to get around the lack of conditional branching in workflows. We have several instances where we want to force a workflow to stop at a certain point, so I am building a custom step to do that.

image

Cool thanks for sharing. And as you gleaned, there is no timeout for incomplete workflows.

Thank you, @filmaj. This was extremely helpful. Like @mcsescott (thank you for asking first), I too am trying to get around the lack of conditional branching in workflows.

One way I have worked around the lack of conditional branching is to encapsulate each "branch" into a separate workflow. Then, using a custom function at the particular branching point, I create a dynamic one-time (no recurrence) scheduled trigger (see our docs on this here - flip the tab in this section to "create a scheduled trigger at runtime") for a few seconds in the future which trips whichever workflow represents the "branch" that I want to run.

Definitely a hack and non-ideal workaround until conditional branching is a first-class feature, which the team is hard at work on.

Going to close this issue as I believe the questions in here have been answered, but if there are any follow ups, feel free to re-open / at-mention me / file a new issue.