ヘルスケアデータを半自動でGCSに投入しGCFを通してRailsにPOSTする

※ ここに書かれているものはGCFが beta の時にかかれているもので正式リリースされた時にはかわっているかもしれません

hatappi.hateblo.jp

以前ヘルスケアデータをGoogleCloudStorage(GCS)にアップロードするプログラムを作成した
そして

hatappi.hateblo.jp

ここでGoogleCloudFunctions(GCF)を使ってサーバーレスにふれた

今回やること

今回はそれらを使ってヘルスケアデータがGCSにアップロードされた際にそのイベントを元にGCFでRailsへのアップロード処理を行う

Rails

Railsに関しては今回POSTで/health_care/uploadにファイルをアップロードをうけつけるcontrollerだけを定義する

# config/routes.rb
Rails.application.routes.draw do
  post 'health_care/upload' => 'health_care#upload'
end

# app/controllers/health_care_controller.rb
class HealthCareController < ApplicationController
  protect_from_forgery with: :null_session

  def upload
    file = upload_params[:upload_file]
    # something
  end

  private

  def upload_params
    params.permit(:upload_file)
  end
end

GoogleCloudFunctions

前回はHTTP Triggerを使用したが今回はGoogle Cloud Storage Triggersを使用する

package.json

{
  "name": "post_health_care",
  "version": "1.0.0",
  "description": "post health care data",
  "main": "index.js",
  "dependencies": {
    "@google-cloud/storage": "^1.1.0",
    "request": "^2.81.0"
  },
  "author": "hatappi",
  "license": "MIT"
}

index.js

const storage = require('@google-cloud/storage')();
const request = require('request');
const fs = require('fs');

exports.uploadHealthCare = function uploadHealthCare (event, callback) {
  const eventData = event.data;
  console.log('bucket is ', eventData.bucket, 'name is ', eventData.name);
  const file = storage.bucket(eventData.bucket).file(eventData.name);
  file.download().then(function(data) {
    const contents = data[0];
    # データを一度tmp領域に保存してそのファイルをアップロードする
    const tmpPath = '/tmp/' + eventData.name.match(/[^\/]+$/)[0];
    fs.writeFileSync(tmpPath, contents);
    const formData = {
      upload_file: fs.createReadStream(tmpPath)
    };
    request.post({ url:'Railsのアップロード先', formData: formData }, function optionalCallback(err, response, body) {
      if (err) {
        console.log('upload failed:', err);
      } else {
        console.log('Upload successful!  Server responded with:', body);
      }
      callback();
    });
  })
  .catch(function(err){
    console.log(err);
    callback();
  });
};

前回のHTTP Triggerの時のように処理を終了したことを明示するためにcallback();を記載する必要がある
これを指定しないと処理が終了せずに後にタイムアウトをむかえて終了してしまう

また今回はファイルをアップロードするために一度tmp領域にファイルを保存した後にPOSTリクエストを行っている
ここに記載されているが、GCFではtmpfsと呼ばれるメモリに保存するマウントポイントが/tmpとして用意されていて使用することが出来る

ここまでくると後はデプロイするだけ

$ gcloud beta functions deploy uploadHealthCare --stage-bucket [codeを保存するGCSのバケット名] --trigger-bucket [トリガーとして監視するGCSのバケット名]

最後に

ここまでくればGCSにヘルスケアデータがおかれるとRailsへのアップロード処理が行われる
ただ今回行った処理はGCSにアップロードする処理をRailsへと向ければよくGCFをはさむ必要はなかったが使ってみたさで今回は行った