Slack 次世代プラットフォーム機能を少しずつ試す - スケジュールトリガー編

こんにちは、Slack の[公式 SDK 開発](https://github.com/slackapi)と日本の Developer Relations を担当している瀬良 (@seratch) と申します :wave:

この記事は [Slack の次世代プラットフォーム機能を少しずつ試しながら、ゆっくりと理解していくシリーズ](https://qiita.com/seratch/items/b1449132add003e61de6)の記事です。

「次世代プラットフォーム機能って何？」という方は、以下の記事で詳しく解説しましたので、まずはそちらをお読みください。

https://qiita.com/seratch/items/ecc16b845483c9d6f9e1

この記事では、[スケジュールトリガー（Scheduled Trigger）](https://api.slack.com/future/triggers/scheduled)の使い方をご紹介します。

### ブランクプロジェクトを作成

いつものようにブランクプロジェクトを作成してゼロからコードを足していきましょう。`slack create` コマンドを実行して、選択肢から「Blank Project」を選択してください。作成したプロジェクトの構成は以下の通りです。

```bash
$ tree
.
├── LICENSE
├── README.md
├── assets
│   └── default_new_app_icon.png
├── deno.jsonc
├── import_map.json
├── manifest.ts
└── slack.json
```

今回はトリガーがメインの記事ですので、ワークフローは非常にシンプルなものにしましょう。

### ソースコードでトリガーを作る

以下の内容を `example.ts` として保存してください。

```typescript
// -------------------------
// ワークフロー定義
// -------------------------
import { DefineWorkflow } from "deno-slack-sdk/mod.ts";

export const workflow = DefineWorkflow({
  callback_id: "example-workflow",
  title: "Example Workflow",
  input_parameters: { properties: {}, required: [] },
});

// -------------------------
// トリガー定義
// -------------------------
import { Trigger } from "deno-slack-api/types.ts";

const trigger: Trigger<typeof workflow.definition> = {
  type: "scheduled",
  name: "Trigger a workflow",
  workflow: `#/workflows/${workflow.definition.callback_id}`,
  inputs: {},
  schedule: {
    // slack triggers create コマンドを実行したタイミングから 60 秒後を指定
    start_time: new Date(new Date().getTime() + 60000).toISOString(),
    end_time: "2037-12-31T23:59:59Z",
    frequency: { type: "daily", repeats_every: 1 },
  },
};

export default trigger;
```

そして `manifest.ts` にこのワークフローを追加します。

```typescript
import { Manifest } from "deno-slack-sdk/mod.ts";
import { workflow as Example } from "./example.ts";

export default Manifest({
  name: "objective-fox-22",
  description: "Scheduled trigger example",
  icon: "assets/default_new_app_icon.png",
  workflows: [Example], // ここに追加する
  outgoingDomains: [],
  botScopes: ["commands"],
});
```

これで準備完了です。`slack triggers create --trigger-def ./example.ts` を実行します。選択肢から `(dev)` という接尾辞がついている方を選択してください。

```bash
$ slack triggers create --trigger-def ./example.ts
? Choose an app  seratch (dev)  T03E*****
   objective-fox-22 (dev) A04FNE*****

⚡ Trigger created
   Trigger ID:   Ft04EJ8*****
   Trigger Type: scheduled
   Trigger Name: Trigger a workflow
```

トリガーが作成されたら、早速 `slack run` を実行して 60 秒後にこのワークフローが実行されることを確認しましょう。以下のように Example Workflow の実行ログが出力されれば成功です。

```bash
$ slack run
? Choose a workspace  seratch  T03E*****
   objective-fox-22 A04FNE*****

Updating dev app install for workspace "Acme Corp"

⚠️  Outgoing domains
   No allowed outgoing domains are configured
   If your function makes network requests, you will need to allow the outgoing domains
   Learn more about upcoming changes to outgoing domains: https://api.slack.com/future/changelog
✨  seratch of Acme Corp
Connected, awaiting events

2022-12-13 11:12:31 [info] [Fn04EYKJ6DKM] (Trace=Tr04EJ8946K1) Function execution started for workflow function 'Example Workflow'
2022-12-13 11:12:31 [info] [Wf04ES573HFY] (Trace=Tr04EJ896CDV) Execution started for workflow 'Example Workflow'
2022-12-13 11:12:32 [info] [Fn04EYKJ6DKM] (Trace=Tr04EJ8946K1) Function execution completed for function 'Example Workflow'
2022-12-13 11:12:32 [info] [Wf04ES573HFY] (Trace=Tr04EJ896CDV) Execution completed for workflow 'Example Workflow'
```

このトリガーは明日また実行されますが、そのときに `slack run` が起動していないとワークフローの実行がエラーになってしまいます。忘れないうちに削除しておきましょう。
（先ほどの出力にも出ていましたが） `slack triggers list` で作成済のトリガーを再度確認して、

```bash
$ slack triggers list
? Choose an app  seratch (dev)  T03E*****
   objective-fox-22 (dev) A04FNE*****

⚡ Triggers installed to the app
   Trigger 1
     Trigger ID:   Ft04EJ8*****
     Trigger Type: scheduled
     Trigger Name: Trigger a workflow
```

その Trigger ID を以下のコマンドに渡します。

```bash
$ slack triggers delete --trigger-id Ft04EJ8*****
? Choose an app  seratch (dev)  T03E*****
   objective-fox-22 (dev) A04FNE*****

🗑️  Trigger 'Ft04EJ8*****' deleted
```

これであと片付けは終了です。

### ファンクションの中からトリガーを作る

次は自前のファンクションの中で API 呼び出しによってトリガーを作成する例です。

```typescript
// -------------------------
// ファンクション定義
// -------------------------
import { DefineFunction, SlackAPI, SlackFunction } from "deno-slack-sdk/mod.ts";
import { workflow as exampleWorkflow } from "./example.ts";

export const def = DefineFunction({
  callback_id: "trigger-creator",
  title: "creator",
  source_file: "creator.ts",
  input_parameters: { properties: {}, required: [] },
  output_parameters: { properties: {}, required: [] },
});

export default SlackFunction(def, async ({
  token,
}) => {
  const client = SlackAPI(token);
  const creation = await client.workflows.triggers.create({
    type: "scheduled",
    name: "Trigger a workflow",
    workflow: `#/workflows/${exampleWorkflow.definition.callback_id}`,
    inputs: {},
    schedule: {
      // slack triggers create コマンドを実行したタイミングから 60 秒後を指定
      start_time: new Date(new Date().getTime() + 60000).toISOString(),
      end_time: "2037-12-31T23:59:59Z",
      frequency: { type: "daily", repeats_every: 1 },
    },
  });
  console.log(`Trigger creation result: ${JSON.stringify(creation)}`);
  if (creation.error) {
    return { error: creation.error };
  }
  return { outputs: {} };
});
```

実際には、前段のファンクションで OpenForm などを使って入力を受け取り、それを元にどのようなトリガーを作成するか決める感じになるかと思います。

ですが、今回の記事のメイントピックではないので、ごくごくシンプルなコード例を共有するだけにとどめたいと思います。ランタイムでトリガーを作成するトピックは別の記事で詳しく解説します。

### 終わりに

いかがだったでしょうか？スケジュールトリガーは、手軽にワークフローの定期実行を行えますので、さまざまな用途に使える便利なトリガーではないかと思います。

例えば、朝会的にチャンネル内で非同期の情報共有を毎朝共有するよう促したり、定期的にデータをチェックして必要に応じて同期や修正を行ったりするのに利用できるでしょう。ぜひうまく活用してみてください。

それでは！