Scheduled Workflows
ワークフローAPIは、外部サービスから公開・起動されるワークフローを構築するのに便利ですが、APIワークフローは、アプリケーション内でワークフローをスケジュールするのにも使用できます。
スケジュールワークフローの使用例
例えば、ユーザーがサインアップした1ヵ月後にトライアルを終了させたり、イベントの1週間前にリマインダーを送信するなど、将来のアクションをスケジュールする必要がある場合、あるいは毎週ニュースレターを送信するなど、いくつかの定期的なイベントを設定する必要がある場合は、スケジュールされたワークフローを使用する必要があります。
これはAPIそのものではありませんが、スケジュールワークフローはAPIワークフローと同じインターフェースを使用して、アプリケーションのバックグラウンドで実行できるさまざまなワークフローを設定します(topnavのページナビゲータ内の「Backend Workflows」ページ)。
ワークフローのスケジューリング
まず、必要なAPIワークフローを構築します。次に、’Schedule API Workflow’アクションを使用して、APIワークフローを現在の日付時刻または将来的に実行するようにスケジュールします。
スケジュールしたいAPIワークフローを選択し、スケジュールする時間を定義します。APIワークフローレベルで定義された様々なパラメータを入力するプロンプトが表示されます。
また、APIワークフローをリスト上でスケジュールしたり、一度に複数のワークフローをスケジュールすることも可能です。パフォーマンス上の理由から、Bubbleはワークフローの異なる実行に時間的な間隔を置くことができます。
APIワークフローをリストでスケジュールするには、必ず特定の物に対するパラメータでエンドポイントを定義してください。そして、リスト上でAPIワークフローをスケジュールする際に、モノの種類、実行するリストを選択し、パラメータに “this thing “を選択できるようにします。APIワークフローは、リスト内の各物事に対して、この物事のコンテキストでよく実行される。
スケジュールされたワークフローをキャンセルする
Schedule API Workflow アクションは、ここで説明するアクションでスケジュールされた ワークフローをキャンセルするために使用できる ID を返します。スケジュールされた API ワークフローのキャンセル」または「スケジュールされた API ワークフローのリストのキャンセル」アクションを使用することで、今後実行されるワークフローを キャンセルすることができます。このアクションは、スケジュールされた ID を受け取ります。
定期的なイベントを設定する
定期的なイベントの設定は、アプリの「Backend workflows」ページで、このタイプのワークフローを作成することから始まります。タイプは “Recurring event “を選んでください。このタイプのイベントは、APIワークフローと似ていますが、1つだけ顕著な違いがあります。パラメータのリストを定義する代わりに、ワークフローがワークフローのモノとして受け取るタイプを定義する必要があります。
定期的なイベントを定義したら、「定期的なイベントを設定/キャンセルする」アクションを使用して、定期的なイベントのスケジュールを設定することができます。このアクションは、イベント、項目、頻度、開始日を指定します。同じアクションで定期的なワークフローをキャンセルできますが、頻度には’none’を選んでください。
繰り返し発生するイベントの頻度を更新したい場合、同じアクションをモノに適用すると、次の発生に対してスケジューリングが更新されるようになります。
予定されているワークフローを見る
ログタブにはスケジュール項目があり、ある日付以降のスケジュールイベントを確認することができます。各行でキャンセルをクリックすると、今後の予定をキャンセルすることができます。これは、上に示したCancelアクションを使うのと同等です。
バックエンドワークフローには、まれにIssue Checkerがワークフローの1つの問題を「wf_param_null」としてフラグを立てるというバグがあります。この現象が発生した場合、サポートに連絡し、該当するワークフローに移動してください。既存のパラメータを削除し、[undo button]ボタンを使用して削除を元に戻します。これで、Backend Workflow の幻のパラメータが削除されるはずです。
再帰的スケジュール型ワークフロー
スケジュールされたワークフローは、再帰的に呼び出すことができます。言い換えると、スケジュールされたワークフローは、将来的に実行されるように自分自身をスケジュールすることができます。
再帰的なワークフローは、実行を停止させる条件に該当するかどうかにかかわらず、開始してから24時間後に終了します。
再帰の非技術的な説明
再帰とは専門用語で、大まかに言うと、コードの塊が自分自身を呼び出して再び実行されることを意味します。実際の例としては、辞書で単語を調べる方法を暗記することが挙げられます。このような場合、最初に従う「ルール」は、「辞書を手に取り、途中まで開く – もし単語が途中よりアルファベットで早い位置にあれば、途中より前に来た辞書の半分でこのプロセスを繰り返し、残りは捨てる、または単語が途中よりアルファベットで遅い位置にあればその逆」である可能性がある。このルールを厳格に適用し続ければ、やがて探している単語を見つけることができるだろう。これは再帰処理の簡単な例ですが、Bubbleアプリで再帰処理を使うと、いくつかの強力な動作が解放されます。
再帰的にスケジュールされたワークフローを使用して、大量のデータを処理することができます。
通常のワークフローは、データの処理に使用できます(例:「リストに変更を加える」)。また、データを後で処理する場合は、「リストにAPIワークフローをスケジュールする」オプションもあります。しかし、大量のデータを処理する場合、変更の適用に時間がかかりすぎると、これらのオプションのいずれかがタイムアウトする可能性があります。
より良いアプローチとしては、データ処理を小さなチャンクに分割し、Bubbleがその中の1つの小さなチャンクに変更を適用し、次の小さなチャンクに変更を適用し、その次の小さなチャンクに適用する、といった方法が考えられます。これは再帰的です。Bubbleは1つのチャンクに変更を適用した後、後の時点で次のデータのチャンクに同じ変更を適用するように自分自身に指示するからです。
ワークフローは、次に作業するデータの「塊」として定義されているものをどのように知るのでしょうか?それは、あなたが用意しなければならないロジックです。例えば、データベースにあるすべての車のデータのフィールドを更新したいとします。しかし、車は何十万台もあるので、一度に更新するとタイムアウトになる可能性があります。
代わりに「data updated」のようなフィールドを作成し、「data updated」が「no」の車の検索に変更を適用し、最初の500エントリに対してのみそれを行うAPI Workflowを作成することができます。更新の一部として、「data updated」を「yes」に設定し、5秒後に同じAPI Workflowを再度実行するようにスケジュールします。再実行の際、”data updated” が既に “yes” に変更されているエントリーはピックアップされないので、ワークフローが何度も実行されるうちに、すべての Cars のリストを通して作業することになる。
(より専門的なユーザー向け:この機能は、より大きなリストに対する「for」ループや「do…while…」ループを作成する方法の一つです).
リスト上のスケジューリングと再帰的なスケジューリングの比較
ここでは、「APIワークフローをリストでスケジュールする」場合と、同じAPIワークフローを再帰的にスケジュールするこの戦術の比較表を簡単に紹介します。
APIワークフローをリストでスケジュールする | 再帰的にスケジューリング |
ワークフローが重なる場合がある | ワークフローは1つずつ実行される |
すべてのワークフローが終了したことを知る術がない | ワークフローは、処理すべきデータがあるかどうかを確認し、ない場合は別の処理を行うことができる |
リストを検索し、すべての項目をスケジュールするのにかかる時間/容量に制限される(最大5分) | 無期限で継続可能 |
短いリスト(50~100項目未満)の場合、より速く、よりシンプルになります。 | 長いリストに対してより高い信頼性 |
ワークフローが並行して実行される場合、多くの容量を消費する可能性がある | 容量の使用は、同時に1つのワークフローに制限されます。 |
再帰的にスケジュールされたワークフローを使用するためのその他のヒント
・スケジュールされたワークフローを繰り返し実行する際に、5秒程度の間隔を空けることから始め、この間隔がアプリのキャパシティに与える影響をテストします(問題がないようであれば、いつでも間隔を短くすることが可能です)。
・ミスをしたために、無限ループに陥ってしまったとお考えですか?そこから抜け出す方法は2つあります。
・[ログ] > [スケジューラ]で、次のスケジュール実行を手動で削除します。
・API ワークフロー自体を修正または削除します。次回実行時には、更新された(または存在しない)ワークフローが使用されます。
・ログ > スケジューラー > 「タスクの一時停止」で、アプリのすべてのスケジュールされたワークフローを一時停止することができます。
スケジュールワークフローの事例とウォークスルー
APIは外部サービスをアプリに接続させるためのものなので、それぞれのケースで実装が異なります。ここでは、実際にBubble APIを使用した3種類の例を紹介します。なお、各例はアプリが有料プランで、APIが有効になっていることを前提にしています。
Stripeのサブスクリプションチャージが失敗したときにユーザーに通知する。
他のサービス側で何かが起こったときに、自分のアプリが何らかのアクションを起こすというのは、Bubble APIの典型的なユースケースです。ここでは、Bubble側とStripe側の両方で、さまざまなステップを説明します。まず、Stripeプラグインがインストールされ、プラグインタブに関連キーが入力されているアプリから始めます。また、支払いワークフローでは、ユーザーのStripe顧客IDをユーザーに保存していると仮定します。Stripeが提供するIDからUser thingに移動し、その人のメールを取得するために、このIDが必要になります。
この例では、アプリのドメインを次のように想定しています。
https://stripeexample.bubbleapps.io
トップナビのページナビゲータからアクセスできるBackend Workflowsページで、バブル側から始めます。Stripeがクレジットカードへの課金に失敗したときに呼び出されるAPI Endpointを定義する必要があります。このAPIワークフローは、顧客にカードを更新するよう促すメッセージとともにメールを送信するアクションを持つ必要があります。それではまず、’chargefailed’と呼ぶ新しいAPI Eventを作成しましょう。
このエンドポイントを公開することで、StripeはWebhook(下記参照)を通じてそれを起動することができます。また、シンプルにするために、認証なしで実行できるようにします。
Stripeのドキュメントを見ると、StripeがWebhookをトリガーしたときに何を送信するかがわかります。Stripeのサーバーは私たちのエンドポイントにリクエストを行い、リクエストの本文にイベントIDを送信します。したがって、idパラメータをtextタイプで呼び出しに追加します。
これで、Send Emailアクションの構築を始めることができます。いくつかのことを行う必要があります。
1.Send emailアクションを使用して、このユーザーにメールを送信します。
2.Stripeから送信されたEvent IDを使用して、Eventオブジェクトを取得します。このイベントには、チャージオブジェクトと顧客IDが含まれています。
3.Bubbleで検索を行い、この顧客IDを持つユーザーを取得する。
4.Write a friendly reminder.
まずはアクションを追加し、Toフィールドに手を入れていきます。この作業では、必要なものから考え、そこから上がっていくことが重要です。そのため、まずはUsersの検索から始め、Customer IDフィールドに制約を加え、StripeからのAPI呼び出しの結果を値として定義しています。以下がその検索です。
preventイベントの顧客IDを取得する。Stripeプラグインは、イベントIDからイベントオブジェクトを取得するための呼び出しを提供しています。Stripe を呼び出すと、イベント ID が検証され、イベントオブジェクトが返されます。このオブジェクトから、StripeのCustomer IDを取得することができます。つまり、ここで必要なのはデータソース「APIからデータを取得する」です。
APIコールは ‘Get Stripe event’ で、Stripeに送信する必要のあるevent_idは、最初のリクエスト(webhook)で取得したものと同じものです。このパラメータはドロップダウンの最初のエントリであり、これを選択します。
この段階で、Stripe Eventオブジェクトを取得したので、あとはCustomer IDを取得すれば、検索の準備が整います。
「メール送信」検索のToフィールドに戻り、ユーザーのメールを取得することができます。検索は、ユーザーのリストを返すことに注意してください。この場合、顧客IDが各ユーザーに固有のものであることは分かっていますが、あるユーザーのリストからそのユーザーに移動し、メールを取得するために、リストの最初の項目を取得する必要があります。
あとは、送信したいメッセージを追加して、アクションを終了します。
Bubble側の準備は整った。今回のワークフローが何をするのか、まとめてみましょう。
1.Stripeがwebhookで送信したイベントIDを取得します。
2.Eventオブジェクトを取得し、Customer IDを取得します。
3.アプリケーションのデータベースを検索し、このカスタマーIDを持つユーザーを取得します。
4.検索でヒットしたユーザーへメールを送信します。
https://stripeexample.bubbleapps.io/api/1.1/wf/chargefailed
これからStripeに向かい、Webhookの設定を行います。必要なのは、チャージに失敗するたびに、このURLへのWebhookをトリガーすることです。ここでこれを行います。
そして、準備万端! チャージに失敗すると、Webhookが起動し、Bubbleからユーザーにメールが送信されます。このようなワークフローの実行は、サーバーログで確認することができます。
月刊ニュースレターの送付
この例では、ユーザーが週1回のメールのオプトインとオプトアウトができるシステムを作成する方法を紹介します。ここでは、毎週のアクションをセットアップするためのロジックとワークフローをカバーします。
まず、アプリのAPIページに向かい、新しい定期的なイベントを作成します。
このイベントを’Newsletter’と呼ぶことにしましょう。ニュースレターの購読は、ユーザーに添付されるので、タイプとしてユーザーを選びます。
このワークフローには、このワークフローに送信されたユーザー(「現在のワークフローのユーザー」)にメールを送信するアクションが1つあります。
次に、アプリ内のページに移動して、このニュースレターのオプトインまたはオプトアウトを選択できるようにします。ここでは、非常にシンプルな「アカウント」ページで、2つのボタンを表示します。
このページには2つのワークフローを追加する必要があります。このページでは、ユーザーはログインしていると仮定し、サンプルページではこれを強制することは気にしません。
最初のワークフローは、ユーザーがオプトインできるようにするものです。ユーザーが「Opt-in」ボタンをクリックしたときにトリガーされ、「Set/Cancel a recurring event」が使用されます。
このアクションは、イベントとモノを受け取ります。この場合、イベントは’Newsletter’で、thingはCurrent Userです。ワークフローは、毎週、翌日の午前9時からニュースレターが送信されるように構築しました。
オプトアウトワークフローは、頻度が「none」になることを除いて、まったく同じ構造を共有している。事実上、これはスケジュールされた定期的なイベントをキャンセルします(最初にイベントがスケジュールされていない場合は、何もしません)。
データベースからデータを読み込むスクリプトを書く
GET/Data APIを使用すると、プログラムによってデータを読み込むことができます。これは別のアプリケーションで行うことができますが、いくつかのスクリプトでデータを保存したり印刷したりするために使用することもできます。この例では、Pythonでどのようにこれを行うかを示します。このスクリプトはyourapp.comというドメインでホストされているアプリのために書いており、我々のゴールはすべての請求書を取得することです。このアプリは’invoice’という名前の型を持っていると仮定します。
APIへのリクエストを行う際、どこから始めるか、そして何個のアイテムを取得するかを定義する必要があります。GET APIからの各レスポンスには、残りのアイテムの数が返されます。この例では、前回の呼び出しの最後のアイテムに1を足したものから開始したいと思います。
#packages to perform the request, handle JSON objects, and encode URLs
import requests
import json
import urllib
session = requests.Session()
#API KEY as defined in the settings tab, so that the script has full access to the data
API_KEY = 'XXXX'
#base endpoint, see https://bubble.io/reference#API.get_api.Endpoint
base_url = 'https://yourapp.com/api/1.1/obj/invoice'
#Query initial parameters. We do not send a limit parameter (default is 100)
cursor = 0
remaining = 100
#we keep making calls till we have no remaining items to fetch
while remaining > 0:
#data we send with the search. Search constraints would be here
params = {'cursor': cursor, 'api_token': API_KEY}
url = base_url + '?' + urllib.parse.urlencode(params)
response = session.get(url)
if response.status_code != 200:
print('Error with status code {}'.format(response.status_code))
exit()
chunk = response.json()['response']
remaining = chunk['remaining']
count = chunk['count']
results = chunk['results']
#we print each object
for result in results:
print(json.dumps(result, indent=4, sort_keys=True))
cursor += count
print('No more entries')
Bubbleのアプリケーションエディターの概要(新しいタブで開く)
このようなスクリプトは、データを印刷する代わりに保存したり、ある制約に当てはまるデータを照会したり、といった使い方ができる(応用もできる)。
【あわせて読みたい】
【参考英語サイト】
https://manual.bubble.io/help-guides/the-bubble-api/scheduled-workflows