Day 176|T-sort稼働CSVの取り込み完了。通し実行と“毎朝ジョブ”を本線化する
こんにちは、こんです🦊
100日チャレンジ2回目のWeek 11 / Day 5(通算 Day 176)です。
Day 175で返品CSV→BigQueryのストリーミング挿入まで通し、今日はT-sort稼働CSV(tsort_logs)の取り込み実装と、全体結合(main実行)+自動実行トリガーまで仕上げました。Week設計でいう「Day 5:全体結合と自動化」のゴール到達です。
🎯 今日のゴール
Box上のT-sort稼働CSV → box_raw_data.tsort_logs へ型変換+insertAllで投入
通し関数 main() を整備(未処理抽出→取得→変換→挿入→記録)
GASの時間主導トリガーで毎朝8–9時の自動運転を有効化(暫定)
🔧 実装ログ
1) T-sort稼働CSV → tsort_logs 取り込み
Day 173で確定したスキーマ(started_at TIMESTAMP, line STRING, status STRING, error_code STRING, duration_sec INT64)に合わせて、ヘッダ正規化&型変換を追加。
function castTsort(row) {
return {
started_at: new Date(row.started_at).toISOString(), // TIMESTAMP
line: String(row.line||'').trim(),
status: String(row.status||'').trim(),
error_code: String(row.error_code||'').trim(),
duration_sec: Number(row.duration_sec||0)
};
}
files/{file_id}/content でCSV本文取得 → Utilities.parseCsv() → 1行ずつ castTsort() → BigQuery.Tabledata.insertAll へ(返品CSVと同じ仕立て)。
ヘッダ揺れ(Started At / started_at)は小文字化+記号除去の正規化で吸収。
2) 全体結合 main()(通し)
Boxの複数フォルダを監視し、未処理file_idのみを処理→DLQ(失敗行)退避→処理済み記録までをワンショット化。
function main() {
const targets = [
{ folderId: getProp('BOX_FOLDER_RETURNS'), table:'ec_returns', caster: castReturns },
{ folderId: getProp('BOX_FOLDER_TSORT'), table:'tsort_logs', caster: castTsort }
];
let summary = {files:0, rowsOK:0, rowsNG:0};
for (const t of targets) {
const files = listNewCsvFiles(t.folderId); // Day174で実装
for (const f of files) {
const text = fetchCsvText(f.id); // Day175で実装
const rows = csvToObjects(text); // header→obj配列
const casted = rows.map(t.caster);
const errs = insertRowsToBQ('box_raw_data', t.table, casted);
markProcessed(f.id); // 冪等
handleInsertErrors(errs, casted, t.table); // DLQへ退避
summary.files++; summary.rowsOK += casted.length - errs.length; summary.rowsNG += errs.length;
}
}
logSummary(summary);
}
方針は「小さく速く」:千行程度/ファイルは1ショット、それ以上は分割(1,000〜5,000行/バッチ)でinsertAll安定化。
3) 毎朝の自動運転(トリガー)
GASの時間主導型トリガーで main() を8–9時帯に実行。まずは1日1回から開始(頻度は運用後に調整)。
function setupTriggerDaily() {
// 既存トリガー掃除は省略
ScriptApp.newTrigger('main')
.timeBased().atHour(8).everyDays(1).create();
}
失敗時はLogger+管理シートへ記録(どのファイルのどの段階で失敗か追跡可能に)。
🧪 スモーク結果
T-sort CSV(数十行)→ tsort_logs へ全件成功
一部の空値(duration_sec空)が0に正規化され、Looker計算上も問題なし(来週、NULL/0方針を正式決定)
main() 実行で返品+T-sortの両方が1回で処理され、処理済みIDもしっかり記録
🧭 運用メモ(初期)
未処理判定はfile_id基準:重複挿入を根元から排除。
DLQ(dead-letter queue):失敗行はシートに退避→次回バッチで修正→再送の逃し道を確保。
“毎朝まわる”価値を最短で実現し、Day 6のLookerプロトタイプへつなぐ。
💡 今日の学び
通しの1本化が最強のデバッグ:段階テストよりもmainで通し、どこで詰まるかを最速で掴むのが早い。
列名揺れは“入口で吸収”:後段(BQ/Looker)に影響させないのが保守コスト最小。
頻度はあとから上げる:まずは毎朝1回で信頼性を固め、必要なら複数回や差分検知強化へ。
🔭 明日の予定(Day 177|Week 11 Day 6)
Looker Studioでのプロトタイプ可視化(返品推移/SKU別/理由別、T-sort時間帯稼働・エラー構成)
共有用テンプレ(期間フィルタ、拠点/ライン切替)の初版作成
データ型の最終擦り合わせ(計算フィールド・日付扱い)
✍️ まとめ
Day 176は、T-sort稼働データの取り込み完了と全体の自動運転までを仕上げ、“置けば朝に溜まる”状態に一歩前進。明日はLookerで“見ればわかる1枚”を形にします。
この1週間で目指す「プロトタイプ共有→次週の改善タネ作り」への道筋が、いよいよ見えてきました。
#100日チャレンジ #Week11 #Day176 #DX実験室
#BoxDataWeaver #BoxAPI #BigQuery #GoogleAppsScript #データパイプライン #自動化 #業務改善
