🦗

リンクの自動ヘルスチェッカー作った

2022/12/27に公開

作ったサービス

シンプルなサービスです
url 入力して登録しておくと、定期的に(現状 1 日 1 回)バックグラウンドでリクエストしてリンク切れ等を起こして無いかチェックするサービスです
それだけ
ブログ等の静的なサービスのお役に立てるかも?

こんな感じです

リンクはこちら
https://linkauto.web.app

ちょっと時間があったので、久しぶり作りました
大体 5 日間くらいかかったと思います

キレてるリンクがあった場合は通知します(今のところ通知方法はメールだけですが、ユーザからの要望次第で slack 等でもできるようにするかもです)

最初は某サービスをパロディして linkedout ってサービス名にしようと考えていたんですが、linkedout という id の GCP のプロジェクトが既に存在し、linkedout-XXXX.web.app みたいなダサい名前になってしまうので linkauto って名前に変えました

システム

簡単なサービスなので、簡単に作れるように工夫しました
サービスの複雑さとシステムの複雑さは比例するという仮説を個人的に持ってます

サービス

大体こんな感じで google 様におんぶに抱っこの構成です
簡単なサービスなので安さと手軽さに重きを置きました

フロントエンド

ホスティングは firebase hosting を使用しました
React(TypeScript)と vite を使いました
フレームワーク的なところで言うと Material UI 、 swr、react-hook-form、 react-router-dom 等を使用しました
あとは基本的な useState、 useCallback、useMemo、 useContext あたりのフック API を使った感じで、特筆すべきことは何も無いですね

エラー監視は Sentry で行なっています

バックエンド (バックグラウンド)

言語は go を選択しました
理由は単に個人的に好きなことと、Cloud Functions の様なユースケースは go が真価を発揮できる場所の一つだと個人的に考えているからです

仕組みとしては
Cloud Scheduler で特定の Pub/Sub のトピックにメッセージを定期的に送信
それをトリガーにして Cloud Functions を動かしています

このやり方は Cloud Functions をバッチ的に実行するやり方の定番みたいです
https://cloud.google.com/scheduler/docs/tut-pub-sub?hl=ja

ちなみに後で知ったことですが nodejs の firebase-functions パッケージ だと ↓ を書いてデプロイすれば Cloud Scheduler のジョブと Cloud Pub/Sub のトピック が勝手に作成されるらしいです...恐ろしや

exports.scheduledFunction = functions.pubsub
  .schedule("every 5 minutes")
  .onRun((context) => {
    console.log("This will be run every 5 minutes!");
    return null;
  });

https://firebase.google.com/docs/functions/schedule-functions
自分の場合は Terraform で Cloud Scheduler のジョブと Pub/Sub のトピックを用意してから go で functions の実装をしました
Terraform そんなに手間じゃないし、function を go で実装したいから全然いいんだけどね...
js 嫌いの自分でもこれはちょっと羨ましいかも

工夫

工夫した点は処理が大きくならないようにチェック対象となるユーザーの抽出とユーザーごとのリンクのチェックは完全に分けて実行しています

関数 1
チェックするユーザーをリスト → リンクチェック用の Pub/Sub トピックが用意してあるので、そこに基本的なユーザー情報を送る
関数 2
上記をトリガーにしてユーザーに紐づくリンクをチェックする

こうすることでメモリや実行時間の点でも気にすることが少なくなります

ユーザの数が増えたり、色々複雑なことをやる必要がでてきたらワークフローエンジンとか使ってやる必要が出てくるかもですが、当分はこれで十分です

Firestore

基本的に RDB を触ってきた人間からすると最初は癖があって戸惑いましたが、少し慣れてくるとこれはこれで面白いなーと感じました
最近仕事でもちょっと使う場面があったのでいい勉強になりました

firestore を触りたいけど全然知らない人はこちらの記事がおすすめです
少し古い記事ですが firestore 入門としてはとてもいい記事だと思います
https://zenn.dev/1amageek/articles/7fdb9b3c8e511d1e36c3

サブコレクションはいいぞ

firestore 使うとバックエンドを用意しなくていいので簡単なサービスを作る上では最高です
ただし rules はガッツリと書きましょう

不満を言うとリージョンが一つしか選べないのがきついです

デプロイ

システムの立ち上げ系は基本的に Terraform で行いました
ボタンを押していくのはきついので基本的には IaC に全部してしまいたいという思いがあるためです
firebase もできる限り Terraform で立ち上げてます
auth 等 firebase はまだ対応されていないリソースもあるのでそこは手動で補いました
hosting は Terraform 公式ドキュメントがあるのに、実行したらそんなリソースないぞって理不尽にも怒られてしまいました...

Cloud Functions のデプロイは Terraform でもできますが、gcloud コマンドで行なっています
理由はそっちの方が楽そうに思えた、それだけです

本番環境へのデプロイは Github Actions に任せています

Hosting は firebase init で選択できる Github Actions のやつを少し改良して使用
https://github.com/FirebaseExtended/action-hosting-deploy

Cloud Functions はこの 2 つと gcloud コマンドでデプロイしてます
https://github.com/google-github-actions/auth
https://github.com/google-github-actions/setup-gcloud
Workload Identity あたりの設定を Terraform でやっていた時に下の様なエラーが出てしばらく足止め食らいましたが、プロジェクトの管理者だかのロールを一度サービスアカウントに付与して、外したら直りました
何だったんだろ?あれは

(gcloud.functions.deploy) User [***] does not have permission to access projects instance [<project>:getIamPolicy] (or it may not exist): The caller does not have permission.

まとめ

セットアップが簡単、料金が安い等 firebase が個人開発で愛される理由がわかった気がします

今後はページを丸々スクレイピングしてそのページ中のリンクや画像のヘルスチェックを行う機能も開発済みですが、様々な外部サービスとの兼ね合いでどういう形でリリースしようかなと考えています

仮にユーザが増えたとしても広告は入れるつもりはないです
汚くなるのが嫌なので (背に腹は変えられんってなって入れるかもしれませんが、基本的には嫌です)
もしマネタイズするなら上限解放のための課金プランでやろうと考えています

需要があれば使ってくださると嬉しいです

GitHubで編集を提案

Discussion