KinstaはWordPressアプリケーションデータベース、さらには無料の静的サイトホスティングソリューションを提供するクラウドプラットフォームです。

そんなKinstaのアプリケーションホスティングとSlackのスラッシュコマンドを統合することで、タスクの自動化と効率の大幅向上を図ることができます。

今回の記事では、SlackのスラッシュコマンドとKinstaでホストするPythonアプリケーションを使って、両者の間にリアルタイム通信環境をセットアップする方法をご説明します。スラッシュコマンドを活用することで、例えば、簡単に商品の作成、照会、削除が行えるようになります。

この統合例を商品在庫の動的な管理等にご自由にご活用ください。

Slackのスラッシュコマンドを理解する

Slackのスラッシュコマンドは、テキストベースのショートカットです。フォワードスラッシュ(/)で始まり、特定のキーワードとオプションのパラメータが続きます。

スラッシュコマンドはアクションをトリガーしたり、Slackインターフェース内の機能と直接やりとりしたりすることができます。例えば、/remindでは、Slackの通知を介して直接リマインダーを設定可能です。

Slackインテグレーションを使えば、アプリケーションに合わせたコマンドを設定することができます。今回の説明では、/check_inventoryスラッシュコマンドやその他のコマンドを使用して、製品アプリの在庫管理や照会を簡単にしたいと思います。

Slackとアプリケーションを統合し、あらゆる業務を効率化することができます。結果的には、コミュニケーションと生産性の向上が期待できるでしょう。

  • 一元化されたコミュニケーションハブ─Slackがチームのための統一型スペースとして機能します。アプリをSlackに統合することで、チャンネルが連動し、会話や情報が一箇所に集約され、効率が向上します。
  • リアルタイムのアップデート─統合型アプリでは、重要なイベントに関するアラートを即座に配信し、全員が情報を把握し、変更やアップデートに迅速に対応できるようになります。
  • ワークフローの合理化─統合により、プロジェクト管理ツールからの通知やCRMソフトウェアのアクションのトリガーなどのタスクが自動化でき、手間のかかる手作業が削減できます。
  • コラボレーションの強化─チームメンバーがSlackから直接アプリにアクセスすることで、シームレスなコラボレーションが促進されます。プロジェクトの共有、ファイル編集、ディスカッションが容易になり、部門を超えたチームワークが活発になるはずです。

KinstaでPythonアプリケーションを構築する方法

Kinstaで製品管理アプリケーションをビルドしてデプロイしてみましょう。そして、それをSlackと統合してスラッシュコマンドを活用していきます。最終的にユーザーはSlackのスラッシュコマンドを使って商品の追加、削除、照会が行えるようになります。

前提条件

この説明を読み進めるには、以下のものが必要です。

まず、KinstaでPythonプロジェクトを立ち上げましょう。以下の手順に従ってください。

  1. GitHubで公開されているKinstaのPythonテンプレートにアクセス
  2. Use this template」>「Create a new repository 」を選択して、スターターコードをGitHubアカウント内のリポジトリにコピー
  3. リポジトリの準備ができたら、ログインするかアカウントを作成してMyKinstaを表示
  4. Gitサービス(BitbucketGitHub、またはGitLab)でKinstaを認証
  5. 左サイドバーの「アプリケーション」を選んで「アプリケーションを追加」をクリック
  6. デプロイしたいリポジトリとブランチを選択
  7. アプリケーションに一意の名前を割り当て、データセンターの場所を選択
  8. 次にビルド環境を設定(今回のデモで推奨されるもの─Nixpacksで「標準」ビルドマシン設定を選択)
  9. すべてのデフォルト設定を使用し「アプリケーションを作成」をクリック

デプロイには通常数分かかり、完了すると、デプロイ情報やアプリケーションのリンクが表示されます。

PythonアプリケーションでSlackインテグレーションをセットアップする方法

まずはSlackアプリケーションを作成し、トークンを使ってPythonアプリケーションに接続するスラッシュコマンドを設定します。Slackアプリの設定は以下のように行います。

  1. Slack APIダッシュボードにアクセス
  2. Create New App」をクリックし、「From Scratch」を選択
  3. Slackアプリに名前を付ける(例:product-inventory
  4. ワークスペースを選択し「Create App」をクリック

次は認証です。

  1. Slackダッシュボードのサイドバーで「Socket Mode」を有効にする
  2. トークン名を入力して「Generate」をクリックし、アプリレベルのトークンを生成
  3. このアプリレベルトークンは、後で環境変数を設定するために保存しておく

スラッシュコマンドの設定方法

アプリのスラッシュコマンドを設定するには、以下の手順に従ってください。

  1. Slack APIダッシュボードの「基本情報」の「機能」セクションに移動します。「Slash Commands」を選択します。

    Slack APIダッシュボードに、機能と特徴を追加するオプションが表示される
    Slack APIダッシュボードに、機能と特徴を追加するオプションが表示される

  2. Create New Command」をクリックして、コマンドを設定します。

    コマンド、簡単な説明、使い方のヒントのオプションがあるSlackの「Create New Command」ページ(また、エスケープチャンネル、ユーザー、アプリに送信されるリンクの詳細、オートコンプリートエントリーのプレビューもある)
    Slackの「Create New Command」ページ

  3. Create New Command」ページで、スラッシュコマンドの情報を入力します。例えば「Command」のフィールドに「/hi 」と入力します。お好みで「Says hello!」などの簡単な説明を追加し、使い方のヒントを入力できます。そして「Save」をクリックします。
  4. サイドバーの「Install App」セクションで、「Install to Workspace」をクリックします。
  5. サイドバーの「OAuth & Permissions」から、ボットユーザーのOAuthトークンにアクセスします。このトークンは、今後参照できるように保存してください。

Kinstaのアプリケーションデプロイメントにトークンを追加する方法

  1. MyKinstaのアプリケーションデプロイの「設定」の下にある「環境変数」セクションに移動します。
  2. 環境変数の追加」をクリックします。

    Slack 環境変数の追加ポップアップに、キー、値、そしてそれらを削除したり、別のものを追加したりするオプションが表示される
    Slack環境変数の追加ポップアップ

  3. 「キー1」には「SLACK_BOT_TOKEN」を、「値1」にはボットユーザーのOAuthトークンを貼り付けます。「キー2」には「SLACK_APP_TOKEN」を、「値2」にはアプリレベルのトークンを貼り付けます。
  4. Kinstaが環境変数を使ってアプリケーションを再デプロイできるように、両方のオプションがチェックされていることを確認した上で「今すぐデプロイする」をクリックします。

リアルタイム通信の実装方法

この説明では、以下のファイルを含むKinstaのPythonテンプレートを使用します。

  • Procfile:アプリケーションを実行するコマンドを指定します。
  • requirements.txt:Pythonアプリケーションに必要な依存関係を指定します。
  • server.py:Pythonアプリケーションのメインファイルで、サーバー側の機能や操作を処理します。

Kinstaでは、アプリケーションをデプロイするときに、リポジトリルートのProcfileに基づいて自動でプロセスを作成します。Procfileには以下のコードが含まれます。

web: python server.py

このコマンドはserver.pyに含まれるコードを実行します。Kinstaでは、デプロイと再デプロイの間にrequirements.txtのPython依存ファイルもインストールされます。

それでは、Boltフレームワークを使ってアプリケーションとのリアルタイム通信をセットアップしてみましょう。以下の行をrequirements.txtファイルに追加して、リポジトリの更新時にPythonアプリケーションにBoltを自動的にインストールします。

slack-bolt==1.18.0
slack-sdk==3.23.0

また、psycopg2ライブラリをrequirements.txtファイルに追加します。これはPostgresデータベースへの接続に使用されます。

psycopg2-binary==2.9.9

KinstaでPostgresデータベースを実装する方法

商品在庫アプリには、スラッシュコマンドがデータベースに追加した商品データを永続化する方法が必要になります。永続データストレージを作成するには、Kinstaのデータベースが使用できます。

  1. まず、コントロールパネル「MyKinsta」のサイドバーにある「データベース」セクションに移動して、そこからPostgresデータベースをデプロイします。
  2. データベースの作成」をクリックします。名前を入力し、データベースの種類を選択して、データベースの情報を入力します。「PostgreSQL」を選択し、希望のサイズを設定します。「データベースのユーザー名」と「パスワード」が自動で生成されます。

    データベースを作成するためのフォーム(フィールドには、データベース名、表示名、データベースのタイプとバージョン、データベースのユーザー名とパスワード、データセンターの場所、サイズが含まれ、フォームの下部には2つのボタンがある─ 「キャンセル」と「続行」
    データベースの作成フォーム

  3. 「続行」をクリックしてデータベースの設定を終了します。PostgreSQLデータベースが作成されるまで少々お待ちください。
    完了したら、データベースに外部からアクセスするために、データベースの「外部接続」セクションに移動し、外部接続文字列をコピーします。
    デプロイしたデータベースダッシュボード(詳細には、リソース、場所、バージョン、作成日、内部接続一覧、接続文字列などの内部接続に関する情報が表示される)
    データベースの外部接続情報

    これで、この接続文字列を使ってPythonアプリケーションからデータベースに接続できるようになります。

  4. Pythonプロジェクトで、データベースの初期化関数のためにプロジェクトディレクトリ内にdb.pyファイルを作成します。以下のコードを追加してください。
    import psycopg2
    import os
    
    # 環境変数から接続文字列を取得
    connection_string = os.environ.get("DATABASE_CONNECTION_STRING")
     
    def get_conn():
       # 接続を作成
       conn = psycopg2.connect(connection_string)
    
       # データベースへ接続を返す
       return conn
         
    def init_db():
       # 接続を取得
       conn = get_conn()
    
       # cursorを取得
       cur = conn.cursor()
    
       cur.execute("""
           DROP TABLE IF EXISTS products;
                       
           CREATE TABLE products (
               id INTEGER PRIMARY KEY,
               name TEXT UNIQUE NOT NULL,
               quantity INTEGER NOT NULL
           );
       """)
    
       cur.close()
       conn.commit()
       conn.close()

    get_conn()関数が呼び出されると、外部接続文字列を使用してデプロイされたKinstaデータベースへの接続を処理して返します。

    init_db()関数はデータベース接続を取得し、データベーススキーマを定義し、変更をコミットしながらテーブルを作成する役割を果たします。init_db()関数の呼び出しは、アプリケーションサーバーを最初にセットアップするときに一度だけ行います。その後の呼び出しでは、get_conn()関数を使用してデータベースへの接続を取得します。

スラッシュコマンドハンドラの実装方法

続いては、アプリケーションサーバーのコードを扱います。

  1. server.pyファイルの内容を削除し、以下のライブラリをインポートします。
    import os
    from slack_bolt import App
    from slack_bolt.adapter.socket_mode import SocketModeHandler
    from db import get_conn, init_db
    from psycopg2 import DatabaseError

    これはSlackアプリの機能、データベース接続、エラー処理に必要になります。

  2. 以下のコードをserver.pyファイルのimport文の後に追加します。
    # ボットトークンでアプリを初期化
    app = App(
      token=os.environ.get("SLACK_BOT_TOKEN"),
    )

    slack_boltAppクラスはSlackアプリのインスタンス作成に使用されます。これが、環境変数SLACK_BOT_TOKENから取得したボットユーザーのOAuthトークンでアプリを初期化します。

  3. 次に、先ほどSlackアプリケーションに追加した/hiスラッシュコマンド用のハンドラをデプロイします。次の行をserver.pyファイルに追加してください。
    # hiはあいさつを返すシンプルなコマンド
    @app.command("/hi")
    def send_hello(ack, respond, command):
      # コマンドリクエストの確認
      ack()
      respond(f"Hello!")

    @app.command()は引数として渡されたコマンド文字列のリスナーを作成し、そのスラッシュコマンドのリクエストに対して以下の関数をマッピングします。send_hello()関数はリクエストロジックを処理するものです。

    また、このコードは、ackrespondcommandリクエスト変数を渡し、関数を使用します。処理を続ける前の最初のステップなので、ackを呼び出してスラッシュコマンドのリクエストを確認し、respondを呼び出してテキストレスポンスを送り返します。

    ユーザーがSlackワークスペースでスラッシュコマンド/hiを入力すると、「Hello!」というレスポンスが返ってきます。

  4. Slackアプリケーションのダッシュボードに戻り、以下のコマンドを追加します。
    コマンド 説明 使用のヒント
    /add_product 在庫に商品を追加 product_id、product_name、product_quantity
    /check_inventory 一致するIDの商品が在庫にあるかチェック product_id
    /delete_product 一致するIDの商品を在庫から削除 product_id

    これで、スラッシュコマンドページは以下のスクリーンショットのようになり、コマンドの一覧とその詳細情報が表示されるようになります。

    スラッシュコマンドのページには、各コマンドの名前と説明、編集や削除のオプション、新規コマンドの作成ボタンがある
    Slack APIのスラッシュコマンドページ

  5. /add_productハンドラをserver.pyファイルに追加します。
    # 商品追加のコマンド
    @app.command("/add_product")
    def add_product(ack, respond, command, request):
     # コマンドリクエストの確認
     ack()
    
     # リクエストからペイロードを抽出
     payload = request.body['text']
     id, name, quantity = [i.strip() for i in payload.split(",")]
      
     # connオブジェクト
     conn = None
    
     try:
       # connを取得
       conn = get_conn()
    
       # cursorを取得
       cur = conn.cursor()
    
       # データベースへの商品挿入
       cur.execute(
         "INSERT INTO products (id, name, quantity) VALUES (%s, %s, %s)",
           (int(id), name, int(quantity))
       )
       
       # postgresqlとの密接なコミュニケーション
       cur.close()
       
       # 変更をコミット
       conn.commit()
       
       # レスポンス
       respond(f"""Added product to inventory:
         id - {id},
         name - {name},
         quantity - {quantity}
       """)
    
     except DatabaseError:
       # レスポンスを送信
       respond(f"Product with ID {id} exists in inventory!")
      
     finally:
       # 接続を閉じる
       if conn is not None:
         conn.close()

    request.bodyがハンドリング処理中にSlackが送信するフルリクエストペイロードにアクセスすることになります。

    ユーザーが/add_productスラッシュコマンドを入力すると、アプリケーションは以下のサンプルJSONペイロードをPOSTリクエストとして送信します。

    {
        'token': , 
        'team_id': , 
        'team_domain': , 
        'channel_id': , 
        'channel_name': , 
        'user_id': , 
        'user_name': , 
        'command': '/add_product', 
        'text': '1, notebook, 5', 
        'api_app_id': , 
        'is_enterprise_install': , 
        'response_url': , 
        'trigger_id': 
    }

    commandtextフィールドが含まれます。commandにはトリガーされたスラッシュコマンドが、textには追加テキストが格納されます。例えば、ユーザーが/add_product 1, notebook, 5 というコマンドを入力した場合、textには「1, notebook, 5」が入ります。

    add_productハンドラは、ユーザーのリクエストから商品のID、名前、数量を抽出し、get_conn()ヘルパ関数を使用してデータベースに接続します。また、商品をデータベースに追加するために、insert SQLオペレーションを実行します。商品IDがすでにデータベースに存在する場合、コードはエラーを処理し、IDはすでに存在する旨を応答します。

  6. 次に、残りのコマンドハンドラをserver.pyファイルに追加します。
    # product_idの在庫をチェックするコマンド
    @app.command("/check_inventory")
    def check_inventory(ack, respond, command, request):
       # コマンドリクエストの確認
       ack()
    
       # リクエストからペイロードを抽出
       id = request.body['text'].strip()
    
       # データベース接続の取得
       conn = None
       try:
           # connを取得
           conn = get_conn()
    
           # cursorを取得
           cur = conn.cursor()
     
           # データベースからIDが一致する商品を取得
           cur.execute(
               "SELECT * FROM products WHERE id=%s",
               (int(id),)
           )
    
           product = cur.fetchone()
    
           # コマンドを閉じる
           cur.close()
    
           if product is None:
               respond(f"No product with matching ID {id} found.")
           else:
               # 商品が存在する場合はタプルを分解
               _, name, quantity = product
              
               respond(f"""Product with ID {id} found:
                          name - {name},
                          quantity - {quantity}
                      """)
             
       except Exception as e:
           print("Connection error: %s", e)
             
       finally:
           # 接続を閉じる
           if conn is not None:
               conn.close()
    
    # 一致するproduct_idをインベントリから削除するコマンド
    @app.command("/delete_product")
    def delete_product(ack, respond, command, request):
        #Acknowledge command request
        ack()
    
        # リクエストからペイロードを抽出
        id = request.body['text'].strip()
        
        # 接続を取得
        conn = None
        try:
            # 接続を取得
            conn = get_conn()
       	 
            # cursorを取得
            cur = conn.cursor()
       	 
            # 商品をデータベースに挿入
            cur.execute(
            	"DELETE FROM products WHERE id = %s",
            	(int(id),)
            )
            cur.close()
            conn.commit()
       	 
            # レスポンス
            respond(f"Product with ID {id} deleted from inventory!")
        except Exception as e:
            print("Connection error: %s", e)
        finally:
            # 接続を閉じる
            if conn is not None:
                conn.close()
    

    これら2つのコマンドハンドラは、それぞれ在庫内の一致する商品IDを問い合わせ、削除する役割を担います。

サーバーの実行方法

  1. データベースの初期化とソケット接続を一緒に行うには、server.pyファイルに以下の行を追加します。
    # アプリケーションを開始
    if __name__ == "__main__":
        # 起動時にデータベースを初期化
        init_db()
    
        # ソケットの接続
        handler = SocketModeHandler(app, os.environ["SLACK_APP_TOKEN"])
        handler.start()

    アプリレベルトークンでSocketModeHandlerを初期化する必要があります。Kinstaアプリケーションにデプロイされた環境変数にアクセスするにはSLACK_APP_TOKENを使用します。

  2. 変更をリモートリポジトリにコミットして、Kinstaに自動デプロイします。これで、server.pyはデータベースを初期化し、ソケット接続が確立されます。そして、KinstaのシステムによりPythonアプリケーションの自動再デプロイメントがトリガーされる仕組みです。

アプリケーションのテストとトラブルシューティング

設定したスラッシュコマンドを使ってSlack上でアプリケーションをテストすることができます。

    1. アプリケーションに紐づけられたワークスペースに移動します。アプリのコマンドを表示するには、スラッシュ(/)を入力します。

      Kinsta-demoチャンネルに、在庫商品IDの確認、商品ID、名前、数量の追加、商品IDの削除、Hiなどのコマンドが存在する
      kinsta-demoチャンネル

    2. 各スラッシュコマンドをテストしてみましょう。例えば、/hi と入力します。すると「Hello!」という応答が返ってきます。

      Hiコマンドに対するレスポンス
      Hiコマンドに対するレスポンス

    3. 同じ商品を2回追加するとどうなるかをテストしてみます。スラッシュコマンド/add_product 1, notepad, 2を2回実行します。
      商品追加コマンドを2回実行した結果
      商品を2回追加する

      上のスクリーンショットが示すように、最初のコマンドはうまくいき商品が追加されました。2回目のコマンドでは、そのIDはすでに存在するという応答が表示されます。

    4. 先ほど追加した商品IDを照会してみましょう。/check_inventory 1と入力してください。
      在庫確認コマンドで商品IDを照会─ID、名前、数量が表示される
      在庫を確認する

      クエリに一致するIDの商品が返されました。

    5. 最後に、追加した商品を削除してみます。/delete_product 1と入力してください。

      商品を削除することでID 1の商品が在庫から削除されている
      商品を削除する

トラブルシューティングの方法

アプリケーションを構築しデプロイする際には、アプリケーションが正しく機能するように、特定のエラーへの対処が必要になることがあります。典型的なエラーの検出と解決には、以下の方法をお試しください。

      • トークンを確認する:Socket Modeを使用したアクセスを有効にするために、connections:writeスコープでアプリレベルのトークンを正しく構成できていることを確認してください。また、アプリクラスに正しいトークンを使用することも重要です。ボットのユーザートークンはxoxb-<...>で始まります。SocketModeHandler クラスには、アプリレベルのトークン(xapp-<...>)を使用します。
      • スラッシュコマンドを確認する:Slackアプリのダッシュボードでスラッシュコマンドを設定し、アプリケーションサーバーのコードで正しいハンドラを設定していることを確認してください。
      • エラー処理を改善する:データベース操作の実行時など、アプリケーションロジックがエラーを正しく処理するようにしてください。

まとめ

今回の記事では、Slackのスラッシュコマンドを使ったリアルタイム通信Pythonアプリケーションの構築方法をご紹介し、アプリケーションをKinstaにデプロイする方法にも触れました。

KinstaでホストしたアプリケーションをSlackと統合することで、スラッシュコマンドを使用して素早く変更を行うことができるようになります。リアルタイムデータへの即時アクセスを確保しながら、インタラクティブ性能とワークフロー効率を高めることができます。コミュニケーションプラットフォームから離れることなく、シームレスに商品在庫を追加、削除、または確認可能です。これにより、多忙な勤務時間中の生産性が向上するはずです。

KinstaのPaaSにはさらに多くの可能性が秘められています。アプリケーションとデータベースを接続し、企業やビジネスの成長を後押しするフルスタックソリューションを展開可能です。さらに初回20ドルはKinstaが負担いたしますので是非ともご活用ください。

Jeremy Holcombe Kinsta

Content & Marketing Editor at Kinsta, WordPress Web Developer, and Content Writer. Outside of all things WordPress, I enjoy the beach, golf, and movies. I also have tall people problems ;).