☯️

Resilireのデータ保守作業3種の神器を紹介します | Resilire Tech Blog

2024/03/21に公開

サプライチェーンマネジメント SaaS のSREエンジニア採用中です!

サプライチェーンリスク管理クラウドサービスResilireでエンジニアをしている@bbbar326 です。
Resilireではエンジニアとして、機能開発やシステム運用やプロジェクト推進などを幅広くやっています。

前回の記事ではResilireがシード期ながらもAuth0を選択した理由について紹介させていただきました。

今回は趣向を変えてResilireのシステム運用の方法についての泥臭い記事を上げさせていただきます。

Resilireのデータ保守作業3種の神器を紹介します

システム運用をしていると、様々な都合により「通常の操作と異なる」データ登録/変更をする必要がある場合があります。

一例ですが、下記のようなケースがResilireでも発生しています

  • ユースケースA: テーブル構造の変更により、リリース作業としてデータパッチを当てたい
  • ユースケースB: データ移行をしたい(お客様の基幹システムのデータやResilire旧システムのデータを一括で登録したいケースなど)
  • ユースケースC: 環境セットアップ作業として、初期設定/データ反映をしたい

これらは、一般的なシステム運用において避けられないものであり、それぞれの特徴に応じて適切な方法で行われることが求められます。

ユースケースごとの特徴と要件ポイント

ユースケースA〜Cの特徴をそれぞれ紹介した上で、実際のデータ保守作業でどのような要件を定義したかを整理しました。

A: テーブル構造の変更によりリリース作業としてデータパッチを当てたい

  • 大量データを扱うことが多い(テーブル内の全レコードが対象になるため)
  • 変更のバリエーションは少ない(追加カラムのデフォルト値の割当など単純な変更のものが多い)

B: データ移行をしたい

  • 大量データを扱うことがそこそこ多い(お客様のデータ量次第で多くなることもある)
  • 変更のバリエーションが多い(CSVなどに記載された多くの情報を多くのテーブルに保存する必要がある)

C: 環境セットアップ作業として初期設定/データ反映をしたい

  • 大量データを扱うことは基本的にない
  • 新規のお客様が導入して頂く度に繰り返し行われる作業

要件×ユースケースの対応表

次の表はResilireにおけるデータ保守作業の一般的な要件と、今回紹介するユースケースごとにどの要件が該当するかをまとめた表です。

要件 / ユースケース A:テーブル変更 B:データ移行 C:初期設定/データ反映
要件1: レビューを通過した変更内容の実行[MUST]
要件2: 社内の権限を持つユーザーに限定できること[MUST]
要件3: いつ誰がそれを実行したかの証跡が残ること[SHOULD]
要件4: 作業を強制終了して中断できること[SHOULD]
要件5: システムリソースへの負荷が少ないこと[SHOULD]
要件6: バリデーションやフック処理など既存処理を再利用したいこと[WANT]
要件7: 属人性を排除して、特定の担当者以外も安全に作業できるようにすること[WANT]

データ保守作業の3種の神器

これらのユースケースと要件を満たす方法として、Resilireでは3つの神器(方法)を用意しました。

  • 神器1: スクリプト実行基盤
  • 神器2: API一括実行ツール
  • 神器3: 社内Admin

image

神器1: スクリプト実行基盤🪞

  • 構成

    • スクリプト実行基盤からデータベースコネクションを取得します。sqlboilerで生成した型定義(通常導線で利用している型定義と同じもの)を使ってデータ取得や加工処理をしてテーブルにデータを登録/更新します。

    • スクリプトのサンプル

      func NewScHistoryMigration() *MigrateScHistory {
      	var (
      		configPath = flag.String("c", "../../../configs/environments", "environmental config path")
      	)
      	flag.Parse()
      
      	// loading to Environment variables.
      	myenv.LoadConfig(os.Getenv("ENV"), configPath)
      
      	cfg := config.InitConfig()
      	writeDB := dbmgr.InitDBConnection(cfg)
      
      	return &MigrateScHistory{
      		db: writeDB,
      	}
      }
      
      func (m *MigrateScHistory) DoMigration(ctx context.Context) {
      	defer func(writeDB *dbmgr.MyDB) {
      		err := writeDB.Close()
      		if err != nil {
      			panic(err)
      		}
      	}(m.db)
      
      	tx, err := m.db.BeginTx(ctx, nil)
      	if err != nil {
      		fmt.Println("failed to start transaction")
      		panic(err)
      	}
      
      	// Get Migration Target Sc Bases
      	scBases, err := m.getMigrationTargetScBases(ctx, tx)
      	if err != nil {
      		fmt.Println("failed to get migration target sc bases")
      		err = tx.Rollback()
      		panic(err)
      	}
      
      	if len(scBases) == 0 {
      		fmt.Println("No migration target sc bases")
      		return
      	}
      
      	err = initScHistories(ctx, tx, scBases)
      	if err != nil {
      		fmt.Println("failed to init sc histories")
      		err = tx.Rollback()
      		panic(err)
      	}
      
      	// 確認
      	result, err := m.getMigrationTargetScBases(ctx, tx)
      	if err != nil {
      		fmt.Println("failed to get migration target sc bases")
      		err = tx.Rollback()
      		panic(err)
      	}
      
      	if len(result) != 0 {
      		fmt.Println("migration failed because there are still sc bases that have not been migrated")
      		err = tx.Rollback()
      		panic(err)
      	}
      
      	err = tx.Commit()
      	if err != nil {
      		panic(err)
      	}
      }
      
      func main() {
      	ctx := context.Background()
      	scHistoryMigration := NewScHistoryMigration()
      	scHistoryMigration.DoMigration(ctx)
      }
      
      
  • 主なメリット

    • システム負荷を見ながらsleepやチャンクサイズの調整が出来るため、大量データ登録に向いている
    • バリデーションロジックなども柔軟に組めて、安全にデータパッチが出来る
  • この方法が向いているユースケース

    • ユースケースA: テーブル構造の変更により、リリース作業としてデータパッチを当てたい

神器2: API一括実行ツール🗡️

  • 構成
    • お客様の基幹システムやResilireの旧システムから吐き出されたCSV情報などをもとに、スクリプトで内容を解析して、プロダクトの通常導線と同様のAPIをコールしてデータを登録します。
  • 主なメリット
    • 通常の機能導線と同じAPIを再利用すれば、フック処理などでデータの更新に伴う処理がある場合でも同じ処理を通ることになり、安全にデータ登録ができる
    • APIを1件ずつ叩く方式になっているので、時間はかかるもののシステムリソース的には負荷分散されている
  • この方法が向いているユースケース
    • ユースケースB: データ移行をしたい

神器3: 社内Admin☯️

  • 構成
    • データベースやAPIを利用して各種情報を取得し、いわゆる管理画面からデータ修正をします(※Resilireでは、QuerierとDashcombというローコードSaaSを比較検討し、結果的にDashcombを採用しました。選定理由などはまた別記事にしたいと思います)。
  • 主なメリット
    • 画面操作でデータ状態を確認しながら作業ができるため、安全に作業ができる
    • 開発者以外にビズメンバーでも作業ができるようになり、会社全体として属人性が排除できる
  • この方法が向いているユースケース
    • ユースケースC: 環境セットアップ作業として、初期設定/データ反映をしたい

まとめ

データ保守要件と各神器の対応関係をまとめると次のような対応関係になります。

要件 神器1:スクリプト実行基盤 神器2:API一括実行ツール 神器3:社内Admin
要件1: レビューを通過した変更内容の実行[MUST]
要件2: 社内の権限を持つユーザーに限定できること[MUST]
要件3: いつ誰がそれを実行したかの証跡が残ること[SHOULD]
要件4: 作業を強制終了して中断できること[SHOULD]
要件5: システムリソースへの負荷が少ないこと[SHOULD]
要件6: バリデーションやフック処理など既存処理を再利用したいこと[WANT]
要件7: 属人性を排除して、特定の担当者以外も安全に作業できるようにすること[WANT]

そしてユースケースに応じて上記の神器を使い分けて運用をしています。冒頭で紹介したユースケース例と改めて整理すると次のような使い分けです。

ユースケース 神器1:スクリプト実行基盤 神器2:API一括実行ツール 神器3:社内Admin
A:テーブル変更
B:データ移行
C:初期設定/データ反映

以上、データ保守作業における3つの方法とResilireの背景をご紹介しました。
より具体的な構成や技術選定理由についてはまた別記事でご紹介できればと思います。

エンジニア採用強化中

株式会社 Resilire (レジリア) では、サプライチェーンリスク管理クラウドサービスResilireの開発メンバーを募集中です。

https://recruit.resilire.jp/for-engineers

まずは情報交換程度に気軽に話して聞いてみたいという方もウェルカムです!

https://youtrust.jp/users/dbe20f6be47eaecdcd61be05c574afc5

Discussion