Talend jobをHerokuで動かしてみる


（本記事は [Heroku Advent Calendar 2019](https://qiita.com/advent-calendar/2019/heroku) 11日目の記事になります）

# はじめに

[Talend Open Studio for Data Integration](https://jp.talend.com/products/data-integration/data-integration-open-studio/)は、GUIベースでデータ連携プログラムを作成できる非常に利便性の高いソフトウェアとして公開されております。
このソフトウェアで作成したジョブは、jarファイルとしてエクスポートして手元で実行させることも可能です。

エクスポートしたjarファイルを実行させる環境としては、ローカルやオンプレはなるべく避けたいところで、何かしらのクラウドサービス上にデプロイして実行させたい...と思うことが多いのではないでしょうか。

そんなわけで、本記事ではエクスポートしたTalendジョブをHerokuにデプロイして実行させる方式について検討したことを紹介します。

# Heroku側でのアプリケーション構成

今回試した構成は、このようなものです。

![talend_job_on_heroku_summary.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1840/0c35bebd-fabc-0779-4f62-221dccd5ff0c.png)

#### (補足)

今回はNode.jsから起動させる方式にしていますが、もちろんJavaアプリケーションとしてTalendジョブを組み込むようにしても良いと思います。
実際に[こちらのブログ](http://sfdcode.com/integration/integration-salesforce-talend-etl-heroku/)で紹介されています。

今回は

* TalendジョブはDev属性以外の人が作る（コードは書けないけど、ツールは使える等）
* 作ったジョブからエクスポートしたjarを受け取って組み込む

と、分担してみるあたりの検討も兼ねて、このような構成にしてみました。

# サンプルとするTalendジョブ

<img width="1222" alt="talend_job_detail.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1840/94960f85-a5bc-53b1-9c15-b70b451c1cc0.png">

今回試すTalendジョブは非常にシンプルなものです。

1. salesforce(DE環境)に接続する
2. ユーザをクエリする(1件だけ取得する)
3. そのユーザに対して、FeedItemを作成する
4. プラットフォームイベントを作成する
    * salesforce側では、プラットフォームイベントを受信するとプロセスビルダーが起動してカスタム通知を送信するようにしています

...といった具合です。
Talend上で作成したジョブをエクスポートするとzipファイルが作成されます。

<img width="426" alt="talend_job_context_menu_to_export.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1840/57c6e8cf-4c57-271e-a045-5ac9f3a922ea.png">

<img width="823" alt="talend_job_export.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1840/b30a897d-52b6-ae81-c7fd-e3955fa40303.png">

そのzipファイルを解凍すると、中にjarファイルと起動用のshファイルがありますのでこれを利用します。
__なお、shファイルは実行可能となるようにしておいてください(念のため)__

<img width="364" alt="talend_job_files.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1840/0484b585-58a3-e886-5e91-d20562c1581a.png">

# Herokuへの実装

<前提>
Heroku Appを事前に用意しておきます。以下、`try-boot-talend`というHeroku Appが存在する前提で進みます。

## 使用するbuildpack

今回使用するbuilpackは以下2つです。

1. `heroku/jvm`
2. `heroku/nodejs`

nodejsアプリを動かすための`heroku/nodejs`の他に、メインとなるTalendジョブを動かすための`heroku/jvm`も使用します。

```bash
$ heroku buildpacks:add heroku/jvm -a try-boot-talend
$ heroku buildpacks:add heroku/nodejs -a try-boot-talend
```

## 使用するAddon

今回使用するAddonは以下になります。

* [cloudAMQP](https://elements.heroku.com/addons/cloudamqp)

メッセージング基盤を提供するaddonになります。実際にはRabbitMQをSaaSとして提供しています。
※合わせてどうぞ -> [新人プログラマに知ってもらいたいRabbitMQ初心者の入門の入門](https://qiita.com/gambaray/items/3cc02b419c860a96bc94)

```bash
$ heroku addons:create cloudamqp:lemur -a try-boot-talend
```

## heroku環境変数

今回は1つだけ追加します。RabbitMQへのQueueのキーを指定しておきます。

```
$ heroku config:set MSG_QUEUE_TOPIC_EXEC_TALEND="talend" -a try-boot-talend
```

## Talendジョブを起動するためのプログラム

大体こんな感じです。

```javascript
'use strict';

/**
 * 
 */
const child = require('child_process');

// AMQP
const amqp = require('amqplib');
const amqp_url = process.env.CLOUDAMQP_URL || "amqp://localhost";
const open = amqp.connect(amqp_url);

/**
 * 
 */
function start() {
  //
  open.then( con => {
    return con.createChannel();
  }).then( channel => {
    const topic = process.env.MSG_QUEUE_TOPIC_EXEC_TALEND;

    return channel.assertQueue(topic).then( ok => {
      return channel.consume(topic, async (msg) => {
        if (msg !== null) {
          const data = JSON.parse(msg.content.toString('utf8'));
          console.log(data);

          await exec_job(data);
    
          channel.ack(msg);
        }
      })
    })
  });
}

/**
 * 
 */
function exec_job (data) {
  return new Promise((resolve, reject) => {
    let res;
    let spawned = child.spawn('/app/custom_notification/custom_notification_run.sh', [data.message])
      .on('close', (code) => {
        if (code === 0) {
          console.log('--------------------- success');
          resolve(res);
        } else {
          console.log('--------------------- failed');
          reject(res);
        }
      });
    
  });

}

//
start();
```

ほぼ[amqp.node](https://github.com/squaremo/amqp.node/#promise-api-example)のREADMEにあるサンプルを流用したものになります。
つまるところは、CloudAMQPのQueueをsubscribeしておいて、何かメッセージがきたらそれに反応して処理を実行する、といったものになります。

ここまで完了したら、worker dynoを起動させておきましょう。

```bash
$ heroku ps:scale worker=1 -a try-boot-talend
```

## 試しに実行してみる

RabbitMQのQueueにメッセージを送ってみましょう

Heroku Appの管理画面からCloudAMQPの管理画面を起動します。

![heroku_dashboard_addon_cloudamqp.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1840/ca4e0fe6-0723-3875-fdae-17b68503cf27.png)

さらにRabbitMQ管理画面を起動します。

![boot_rabbitmq_manager.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1840/282fc51a-2897-8414-5eb4-fcd2951b32d1.png)
　↓
![rabbitmq_manager_queue.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1840/1136c0e7-3f7e-d1f0-0547-5f373c193df7.png)

`talend`というQueueが作成されているのが確認できます。（たぶん）
そのQueueに対して、メッセージを発行してみましょう。

![rabbitmq_publish_message.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1840/f9f7a16c-d760-ce86-b487-e7473367da0e.png)

このQueueを購読しているworkerが反応してtalend jobを起動します。
その結果としてChatterやカスタム通知にメッセージが作成されました！

![sfdc_chatter.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1840/a7e62b95-95bc-c563-5900-4c2c34f3b07e.png)

![sfdc_notification.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1840/1b77cca6-dbdb-6198-5cf6-1e48bfb4bbb4.png)

## (追加)

今回は、RabbitMQの管理画面からメッセージを発行しましたが、ある特定のエンドポイントにPOSTされると、RabbitMQのQueueにメッセージを発行するWebアプリを用意すると、色々と利便性が高まると思います。

また、本記事ではTalendジョブに関するjarファイル群はリポジトリ内に格納しましたが、例えばS3に格納しておいてHeroku Appのビルド内でS3からダウンロード＆展開...という具合にしたりすると、もう少しスマートになるかもな、と（ぼんやりと）考えてます。

ちなみに、今回のサンプルは [こちら](https://github.com/takahiro-yonei/try-boot-talend-on-heroku) でも確認できます。

# おしまい

Talendジョブを実行させるための環境としてHerokuも活用できるのではないか？という検証でした。可能性はあるにせよ、まだ悩ましいところ（Talendジョブのソースコードをどう管理するか？などHeroku以外の部分も...）はありますので、継続して検討していきたいと思います。

それでは引き続きHerokuとｷｬｯｷｬｳﾌﾌして、さらなる高みを目指しましょう！
（知らんけど）