IBM CloudのFunctionsを使って、サーバー無しでコード実行する

# IBM CloudのFunctionsを使って、サーバー無しでコード実行する
IBM Cloud のサーバーレスでコードを実行できるサービス Functions（FaaS）サービスを使って、毎時00分になったらNoSQLのCloudantデータベースに値を書き込むサンプル。LinuxのCronみたいな使い方ができる。

#### 悲しいお知らせ： IBM Cloud Functionsは2023年12月28日でサービス提供が終了になりました。今後は、IBM Cloud Code Engine を使います。

### Functionsで何ができるの？
AWS Lambda, Azure Functions とほぼ同じサービス。Linuxサーバーが無くても、さまざまなイベントをトリガーに軽量なコードを実行することができる。

### 実際には何に使ったの？
IoTデータのグラフを表示するWEBアプリを試したくて、データはダミーでいいのだが、時系列の経過と供に追加される値が欲しかったので、毎時00分にダミーデータを出力させてみた。コードはこの後、拡張していくのだが、一番シンプルなコードで記事化しておく。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189936/066e40fc-0aff-fb87-6060-edd4af38ec6f.png)

### 起動できるイベントの種類
1. Github
2. イベントストリーム
3. スケジュール（Cronみたいな定期的に実行）
4. オブジェクトストレージ
5. NoSQL（Cloudant）
6. モバイルプッシュ

### 無料枠を利用できる
メモリ400,000GB秒までが無料と記載されているがムズイ。例えば、メモリ256MBでコード実行時間10秒の時、1ヶ月に45,000回実行するときは無料だ。45,000回というのは毎分であり（＝60分x24時間x31日間）この時メモリ115,200GB秒だろう。この条件でコード実行時間が39秒を超えると有料になったが、それでも70円/月くらい。

## Functionsの初期設定
IBM Cloud 管理ポータルで新しいリソースを追加する。Functionsの場合は、最初にIAM管理される「名前空間」を作ります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189936/2528e61e-23b3-b505-5a77-c227cc50f03d.png)
好きな名前を定義して、リージョンを選びます。ロケーションって書いてありますね。東京リージョンを選びました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189936/df38fb8a-df86-4c44-dfd8-9f9e50c895c3.png)

### アクションの作成
アクション名を定義してランタイムを選びます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189936/47d95f71-b3ee-f66a-ab87-c9d35ef64796.png)
こんな選択画面（↓）が表示されますが、とりあえずアクションを選びます（あとでトリガーを設定する）。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189936/d883afd2-76a5-58ee-1bbe-dfd11868836a.png)

### コードを記述
ランタイムを選んでアクション作成ボタンを押すと、すぐにコード記述する画面になります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189936/d7acfa29-78b7-ac6f-5cbd-f737b9158603.png)

コード記述欄には、最小のひな形が記述済みです。

▼pythonの場合

```
# main() このアクションを呼び出すときに実行されます
# @param Cloud Functions アクションは 1 つのパラメーターを受け入れます。
# このパラメーターは JSON オブジェクトでなければなりません。
# @return このアクションの出力。この出力は、JSON オブジェクトでなければなりません。

import sys

def main(dict):
    return { 'message': 'Hello world' }
```

▼ Node.jsの場合

```
/**
  * main() このアクションを呼び出すときに実行されます
  * @param Cloud Functions アクションは 1 つのパラメーターを受け入れます。
  * このパラメーターは JSON オブジェクトでなければなりません。
  * @return このアクションの出力。この出力は、JSON オブジェクトでなければなりません。
  */
function main(params) {
	return { message: 'Hello World' };
}
```

## FunctionsのPythonコードでCloudantにドキュメント１個を書き込みするコード

```
# IBM Cloud, Functions アクション
import sys
import datetime
import os
import random

from cloudant.client import Cloudant
from cloudant.error import CloudantException
from cloudant.result import Result, ResultByKey

# DBアクセス認証
serviceUsername = "apikey-v2-***************************"
servicePassword = "*************************"
serviceURL = "https://apikey-v2-2v**********-bluemix.cloudantnosqldb.appdomain.cloud"

def main(dict):
    # DBに接続する
    client = Cloudant(serviceUsername, servicePassword, url=serviceURL)
    client.connect()
    myDB_kano = client.create_database("first-db")

    # 新しいドキュメントを作成する
    objToday = datetime.datetime.today()
    strTemp = str(objToday.year) + str(objToday.month) + str(objToday.day) + str(objToday.hour) + str(objToday.minute)
    strComment = random.random()
    jsonDocument = {
        "_id": ":".join(("docid", strTemp)),
        "table": 'hogehoge',
        "comment": strComment
    }
    newDocument = myDB_kano.create_document(jsonDocument)
    
    return { 'message': 'Cloueantにドキュメント１個追加したよ' }
```

## コード実行を起動するトリガーを追加
［トリガーの追加］ボタンを押して、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189936/ea703c7f-4b37-7c71-7bae-2301a2498dc2.png)

### イベントを選びます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189936/e4ba483f-6a03-d999-b510-c17ebfab71ae.png)

### 毎時、毎分、もしくは曜日、その組み合わせは［Periodic］を選びます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189936/03bc9682-9066-3644-6fb1-19653c2c09b1.png)

#### あとでトリガーのパラメータを見直しするGUIが見つからないので、トリガーの名称に「Every Hour」など分かりやすく定義することを強く推奨します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189936/da0cd4c0-6712-b359-a9fb-96ee0062078b.png)

### 正しく動作するかテスト
［起動］ボタンをクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189936/30073d5b-4675-da1b-28cc-9c32e659e972.png)

応答があるまで待つ。。。。7-8秒かかった。。（↓）これ成功の場合
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189936/37171f86-a0af-45e1-3103-16fd3c8d0b96.png)

失敗した場合（↓）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189936/6c9a9fff-a01b-5111-a0d2-14e049ff3c27.png)

### トリガー駆動も、NoSQL（Cloudant）にドキュメントが追加されているのでテスト成功
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189936/a3525cd1-a1f3-4a81-1339-3a77fa464841.png)

## まとめ
このコードは毎時、データを追加するだけの簡単なスケジュール処理を実行できた。

- 駆動するイベントは、Githubやストレージなどさまざまあり
- コードのランタイムは、Node.js, Python, Ruby, Swift, PHP, Goとさまざまに選べる
- Functionsの可用性は高そうだ。東京リージョンで単一障害点を回避しつつ、リージョン丸ごと災害した時はヨーロッパに自動的にフェイルオーバーできるようにFunctionで実行するコードが自動的に同期とられている。

▼Functions入門ドキュメント

https://cloud.ibm.com/docs/openwhisk?topic=openwhisk-getting-started