本記事は私の所属しているコミュニティ:ノンプログラマーのためのスキルアップ研究会 の『ノンプロ研 Advent Calendar 2020』15日目の記事です。

頑張って今年もアドヴェントやってますので、ぜひノンプロメンバーの記事をいろいろ読んでみてください。一年の振り返りから、いろいろ試行されたメンバーの発見なんかも知見になっているかと思います。
さて、私もノンプロメンバーなので、今年はアドベント記事を1つ書くことになりました。正直ネタがねぇなぁ。。。ってなっていたので、ちょっとみなさんに知ってもらってもいいかなという内容をテーマに記事を書くことにしました。結構個人的には力作ですw
FaaSって便利でっせって感じの記事と、GCP cloud functionsを利用したサンプルの紹介です。では、いってみましょうw
そもそもFaaSって何?
IaaS・PaaS・SaaSまでは聞いたことあるけど、FaaSってなんだよ、ってかXaaSって増えすぎじゃない?って思うノンプロのみなさん、正しいですw XaaSは今もいろんなパターンが増えてますw BaaS(Backend as a service)、MaaS(mobility as a service)、CaaS(container as a servie)など、XaaSは毎年のように増えていってますw
そこの中からノンプロでも利用する価値がありそうなサービスとして、FaaS(Function as a service)を紹介していきたいと思います。
FaaSの概要
FaaSは「Function as a Service」の略で、サーバレスで利用できるクラウドサービスのことです。
https://it-trend.jp/paas/article/301-0019
とりあえず、引用から開始しましたが、まー、ざっくりとはサーバレスで利用できるクラウドって理解では大枠としては正解です。ただ、それだと他にもあるよねってなります。
FaaSの特徴としては、関数(function)だけを開発者側が管理すると言う点がざっくりざっくりの理解ではいいのではないかなぁと思います。
また、イベントが発生したら、関数を実行してくれるというのが基本的な作りです。これってどこかで聞いたことありません?
ざっくりいってしまうと、webhookみたいなものだと理解してください(かなりざっくりですが汗)。ほら、ノンプロでも使えそうw
FaaS紹介:GCP cloud functions
GCPで提供されているcloud functionsの説明などは以下のページをご参照ください。

その他のメジャーなFaaS
hook.io
FaaSのはしりとも言われているhook.ioです。webhookというフレーズはよくslackとかでも聞きませんか?
AWS lamda
AWSが提供するFaaSです。ストレージ等をAWSご利用の方は、lamdaをご利用いただくといいかなと思います。

GCP cloud functionsを使って定期実行してみよう
対象とするのは以下の記事で紹介したtdnetのAPIにしてみましょう。
利用するのは以下の2つです。
・cloud functions(python3.8) ・cloud scheduler(イベント発生用、localのcron相当だと思ってください)
functionsを動かすためにschedulerでpub/subを経由して、event発生させて、動作させていきます。
動作イメージとしては以下のような形です。

functionsで利用するコードの紹介
基本は参照記事で紹介したコードと同様なのですが、functionsで実行するために一部実行部分のコードをif __main__からdef(関数)に変更しています。なぜ変更する必要があるかは、コードみた後に説明します。
import requests
import pprint
import json
def get_data_from_yanoshin():
"""
yanoshin APIからデータを100件取得してcontentを返す
:return: dict
"""
base_url = "https://webapi.yanoshin.jp/webapi/tdnet/list/"
condition = "today"
format = "json"
query = "limit=100"
res = requests.get(base_url+condition+'.'+format+'?'+query)
res_loads = json.loads(res.content)
pprint.pprint(res_loads)
return res_loads
def pickup_growth_possibility_material(data):
"""
成長可能性に関する説明資料
:param data: dict
:return: list
"""
output = []
for x in data['items']:
if x['Tdnet']['title'] == "成長可能性に関する説明資料":
output.append([x['Tdnet']['company_name'], x['Tdnet']['document_url']])
return output
def send_email(data):
# メール送信関係
import smtplib
from email.mime.text import MIMEText
from email.header import Header
from_adress = "gmail_adress" # 送付もとメールアドレス、gmailを前提
from_adress_pass = "app pass" # Google accountから発行されるアプリパスワードに変更(2要素認証)
to_adress = "gmail_adress" # 受信メールアドレス
string = ""
if len(data):
for i in range(len(data)):
string = string + str(data[i][0]) + "\n" + str(data[i][1])
else:
string = "本日は対象データがありません"
msg = MIMEText("新規成長性説明資料。\n\n" + string, "plain")
msg["Subject"] = Header("from_bot 成長性説明資料")
smtp_obj = smtplib.SMTP("smtp.gmail.com", 587)
smtp_obj.ehlo()
smtp_obj.starttls()
smtp_obj.login(from_adress, from_adress_pass)
smtp_obj.sendmail(from_adress, to_adress, msg.as_string())
smtp_obj.quit()
def event_call(event, context):
data = get_data_from_yanoshin()
pickup_data = pickup_growth_possibility_material(data)
send_email(pickup_data)
なぜ__main__ではダメなのか?
さて、今回利用しているのはあくまでFaaSです。Function as a serviceということで、関数を利用するものです。そのため、実行する対象として指定するのはあくまで関数になります。
ということは、__main__だとファイル自体を呼び出した時に、どれを実行するかというだけで、明確にどの関数と指定ができません。なので、今回はdef event_callとして実行関数を定義しています。
実行関数で利用する引数は固定してください
さて、もう一個注意点として、実行関数として利用するevent_call関数には今回eventとcontextを引数として渡しています。これは、使いはしないのですが、pub/subを経由したschedulerの実行においては、必要な引数なので、そのまま設定しておいてください。
本来的にはeventやcontext(schedulerでpayloadとして渡すもの)などを活用してfunctionsを活用するとより便利ですが、今回はcronの代替としてcloud functionsを利用しますので、活用していません。興味ある方は調べてみてください。
Cloud Functions:実際の設定内容
さて、コードの部分だけ説明してきたので、あとは実際の設定についてもみていきます。
1st step: cloud functionsの立ち上げ
まずは、GCPにログインして、利用するプロジェクトを選択した上で、メニューバーからcloud functionsを選択します。

2nd step: cloud functionsの構成設定
関数名は自由に付けてもらってOKです。
トリガーだけ、気をつけてください。今回のケースではpub/subを利用しますので、cloud pub/subを選択してtopicを作成してください。
このtopicの名前が後ほどschedulerで設定するtopic名になります。別に名前自体はなんでもいいですが、schedulerでも利用するので忘れなければOKです(別に忘れても後から見返せばいいだけですけどw)

設定したら、【次へ】をクリックします。
3rd Step: cloud functions コードの設定
コードの設定に関しては、以下のような画面で登録します。今回はcloud source repositoryは使わず、インラインエディタ(GUIで直接編集)でコードを登録していきます。

さて、コードの設定で注意する点は以下です。
ランタイムの選択
Go, Java, Node.jsなどが選べます。pythonは3.7と3.8が対象となっています。今回は3.8を利用します。
エントリポイントの選択
エントリポイントというのが、実行する関数名になります。そのため、今回はevent_call関数を選択します。ここはドロップダウンとかではないので、間違えないようにコピペしとくのが安全です。
ソースコードの構成
さて、ここも一点注意事項があります。functionsではpipなどのライブラリ管理ツールが使えません。というか、root directoryにあるrequirements.txtを読み込んでライブラリ管理を行います。
そのため、ローカル環境でコードを作成した後、以下のようなコマンドをターミナルで実行して、requirmetns.txtファイルを作成しておくことをお勧めします。
pip freeze > requirements.txt
これで、作ったファイルをコピペします。
なお、別の.pyファイルを使ってコードを作ってインポートしたい場合は、以下のソースコードの構造というページをご確認ください。

4th Step: cloud schedulerの設定
さて、次はcloud schedulerの設定です。メニューバーから、cloud schedulerに移動していることを前提に解説していきます。この画面をfunctionsで探してないぞーって文句言うのはやめてくださいw
ジョブを作成と言うボタンをクリックすると以下のような画面が表示されます。

この画面で、以下のように入力していきます。肝となるのは頻度・ターゲット・トピックの3点です。

それでは、早速肝となる頻度などの設定方法について紹介していきます。ここら辺はcron知ってる方だとイメージは非常にしやすいと思います。
Cloud scheduler: 頻度の設定
頻度の設定は、まさにcronの設定そのものです。慣れている方は普通のcronだと思って設定してもらえればOKです。cronに慣れていない方は以下のイメージで設定していきましょう。ちなみにこの形式をUnix-cron形式っていいます。

*5つを使って日時を設定していきますが、それぞれの意味合いは上の画像の通りです。各項目は以下の設定が可能です。
項目 | 有効な値の形式 |
---|---|
分 | 0-59 |
時間 | 0-23 |
日 | 1-31 |
月 | 1-12 |
曜日 | 0-6(日曜日から土曜日) |
Cloud scheduler: ターゲットの設定
選択肢は以下の3つが与えられています。今回はその中から、Pub/Sub(publisher/subscriber)を利用します。メッセージング経由で実行する形です。
対象 | 実行手段 |
HTTP | ジョブが接続するエンドポイントの完全修飾 URL を指定、 methodはPOST |
Pub/Sub | ジョブの公開先トピックの名前を指定 |
App Engine HTTP | ジョブが接続する App Engine エンドポイントの相対 URL を指定。デフォルト値 / を使用する場合、ジョブは PROJECT-ID.appspot.com を使用 |
個人的にはApp Engine HTTPで使うケースが多いですが、Pub/Subも結構利用します。
Cloud scheduler: トピックの設定
今回のcloud schedulerとcloud functionsを連携させるための肝となるトピックの設定となります。
2nd step: cloud functionsの構成設定で設定した、トピック名をここで指定します。ここ間違えると動きませんのでご注意を。
実行結果を確認する
最後は実行結果の確認です。一応コードの最終結果はメールで送られてくることになるので、表示されるメールをみていきます。実際には新規上場会社が11月末から12月15日までないので、ブランクの結果が返ってきています。(この記事の公開日はアドベントの関係上12/15ですが、書いてるのは12月上旬でして。。)

一応メールが飛んできていますよ、って言うくらいの結果報告です(実行はテスト実行のものです)
まとめ
さて、アドベントカレンダー記事として、FaaSサービスの紹介と実際例として、GCP Cloud Functionsを利用したスクリプトや設定を紹介させていただきました。
ちょっと一記事に入れ込む内容ではなくて、かなーり長くなってしまいました。。まぁご容赦ください。
年明け以降で、ノンプロメンバーやノンプログラマーの皆さんの中で、一人でも多くの方がFaaSに興味を持ってもらって、実際に触ってみてもらえたら個人的には嬉しいです。GASもいいですが、今の時代多くの選択肢が提供されていますので、いろいろな選択肢を少しづつ触れていくとやれる範囲が広がっていくかなと思います。
そんなかんなで、アドベントカレンダー15日目の記事でした。最後までお読みいただいた皆様、ありがとうございました。