思考ログ:マルチテナントアプリケーションは難しいんだなぁ(あるいはやっぱり知識は大事という話
公開日時:
唐突にマルチテナントアプリケーションをやりてぇとなった。正確にはマルチテナントアプリケーションを実現する機構を作りてぇとなった。 (別にマルチテナントなプロダクトを作りたいわけではない)
というわけでマルチテナントアーキテクチャを実現する手法はいろいろあると思う。 アプリケーションのレイヤーでやったりとか最近(?)だとtoB向けではあるがクラウドがそのあたりを吸収してくれたりする。AWS でいうところの CloudFront SaaS Manager とか。
もちろん双方向き不向きがある。まぁでもマルチテナントアプリケーションの実装となったときに大体思いつくのは前者かな(当私比)。もちろんこれは条件によって変わってきて、実は私がやるようなものは CloudFront SaaS Manager を使ってアプリケーションはシングルテナント用に組むほうがスケールしたりする。
話を戻して、私は Laravel をよく使うのだけれど、Laravel には Tenancy for Laravel という素晴らしきパッケージがあり、割と雑にマルチテナントなアプリケーションが実現できる。今だから言える。マジですげえ。 これをふと Hono で実現したくなった。やった。結論としては諦めた。
諦めた理由は色々あるはずなのだが今この文章を書いているリアルタイムではうまく言語化できていないので、どうやって実現しようとしたかを淡々と書いてみようと思う
大まかな全体像としては以下のようなものになった。
[HTTP Request]
|
v
[Tenant Middleware]
|
v
[Resolve tenant (first-win chain)]
|- by subdomain
|- by JWT claim
`- by header
|
+--> no tenant resolved ---------------------> [404 Not Found]
|
v
[Resolved Tenant ID]
|
v
[Validate via Tenant Registry]
|
+--> tenant not registered ------------------> [404 Not Found]
|
+--> tenant is suspended --------------------> [404 Not Found]
|
v
[Attach Tenant Context to request]
|
v
[Application Route / Business Logic]
こう書くとえらく単純なのだが、実際最低限として作ろうとしたものは二つしかなくて、
テナント ID を解決する Resolver と、テナントを実際に取得して操作する Registry で、 createTenantMiddleware にそれらを入力として渡すことで環境に合わせた Middleware を作成する、
というだけのもの。
たしかこのあたりを思考しているときに「Drizzle でテナント管理と実テナントのマイグレーションをどのように管理できるのだろう」とか「テナント管理中央 DB はどこまで何をやるべきなんだ…。」とか、「このパッケージ自体に永続的に依存しないでもいいように分離可能性を上げておきたいな…」とか「一 DB でのマルチテナントはどうすれば…」などetc…複数の思考が同時に走った結果、脳で扱えるコンテキストを超えてしまったみたいなところがある。 特に上記に挙げた課題が独立せずに相互に関係しあっている可能性を考慮した結果、組み合わせ爆発を起こしてしまった。 あとはこのミドルウェアはマルチテナントの中でもどこまでを対象にするか、みたいなのもよく考えたら決めたなかったのも大きいと思う。
ここまで書いて思ったのだが、いつもやっている仕事はもう少し複雑でもうまく扱える気がしていて、なんでじゃあこうなった(語彙力)となったときに、私はマルチテナントを扱う定石を知らないということに気づいた。 結果として可能性を0から網羅しようとした結果、思考のショートカットができずに爆散したのだと思う。
生成AIに聞けばいいやんけと思って聞いたのですが、聞いたところでそれが本当に妥当なのかの検証ができなかった。 私はそういう検証不可能な状態でえいやと先に進めることができない(思考を放棄できない)質なのを思い出した。
というわけでちゃんと定石を知って思考をチューニングしましょう。 探したらちゃんとありました。
こうして新たなタスクが追加されましたとさ。ちゃんちゃん。
上記が今回書いた思考ログです。この思考ログからタスクをブレイクダウン、進めるべき順番に並べてください。