実案件/ポートフォリオ

“落ちない”社内自動化3選:再実行安全・ロック・JSONログで回す設計とテンプレ

社内の自動化、まず何から作ればいい?

ちゃんと動き続けて、運用が楽になる設計が知りたい…!

そんな悩みに対して、現場で短期に価値を出しやすい“3つの自動化”と、そのまま使える設計&コードの型をまとめました。

この記事でわかること

  • まず作るべき自動化3選(定例レポート/価格・在庫監視/データ同期・バックアップ)
  • 落ちない運用の型(再実行安全・排他・構造化ログ・レート制御)
  • コピペで動くテンプレコードと、社内運用への載せ方(スケジュール・通知)

まずは“落ちない”ための前提

自動化が炎上する典型は、二重実行での破損沈黙クラッシュ規約違反や高負荷の3つ。対策はコードの書き方で先回りできます。ここで示すテンプレは、idempotent(再実行安全)+排他ロック+JSONログ+通知+上限付きバックオフが標準装備です。

落ちない自動化の共通原則

  • 入力→処理→出力の境界を明確化(データ破損を防ぐ)
  • 再実行安全(同じ入力なら同じ成果物)
  • 排他制御(ロックで二重起動を抑止)
  • 観測可能性(JSONログ+相関ID、ERROR以上は通知)
  • 静かに動く(レート制御、規約順守)

ふみとの現場メモ:ある会社で朝の定例が二重起動してExcelが壊れたことがありました。「原子置換(tmpに書いてから置換)」「ロックファイル」を入れたら翌日からピタッと収束。以降、テンプレ化しています。

まず共通ユーティリティをコピペ

以下をutils.pyとして保存してください。ロック・原子書き込み・JSONログ(回転)が入っています。

from pathlib import Path
import tempfile, os, time, json, logging
from logging.handlers import TimedRotatingFileHandler

class FileLock:
def **init**(self, path: Path, timeout: float = 3):
self.path, self.timeout = path, timeout
self.fd = None
def **enter**(self):
start = time.time()
while True:
try:
self.fd = os.open(self.path, os.O\_CREAT|os.O\_EXCL|os.O\_RDWR)
os.write(self.fd, str(os.getpid()).encode())
return self
except FileExistsError:
if time.time() - start > self.timeout:
raise TimeoutError(f"lock busy: {self.path}")
time.sleep(0.5)
def **exit**(self, \*exc):
try:
os.close(self.fd); os.remove(self.path)
except Exception:
pass

def atomic\_write\_text(path: Path, text: str, encoding="utf-8"):
path.parent.mkdir(parents=True, exist\_ok=True)
with tempfile.NamedTemporaryFile("w", delete=False, dir=path.parent, encoding=encoding, newline="") as tmp:
tmp.write(text); tmp\_path = Path(tmp.name)
os.replace(tmp\_path, path)

# JSON構造化ロガー(回転)

log = logging.getLogger("job"); log.setLevel(logging.INFO)
handler = TimedRotatingFileHandler("logs/job.log", when="midnight", backupCount=7, encoding="utf-8")
class JsonFmt(logging.Formatter):
def format(self, r: logging.LogRecord):
payload = {"ts": self.formatTime(r, "%Y-%m-%dT%H:%M:%S%z"), "lvl": r.levelname, "msg": r.getMessage(), "module": r.module, "line": r.lineno}
if r.exc\_info:
payload\["exc"] = self.formatException(r.exc\_info)
return json.dumps(payload, ensure\_ascii=False)
handler.setFormatter(JsonFmt()); log.addHandler(handler)

自動化ツール3選:要件→設計→テンプレコード

① 定例レポート自動化(CSV→集計→Excel→メール)

要件例:入力はdata/in/sales.csv、出力はout/report_YYYYMMDD.xlsx。毎朝6:10に完了。ERROR以上は通知。

設計ポイント:pandasで集計し、xlsxwriterでサマリ+明細。ロックで二重起動を防止し、引数で入出力や日付を指定できるようにします。

import argparse
from pathlib import Path
import pandas as pd
from utils import FileLock, log

DEF\_IN = Path("data/in/sales.csv")
DEF\_OUT = Path("out/report.xlsx")

def build\_report(src: Path, out\_xlsx: Path) -> dict:
df = pd.read\_csv(src, parse\_dates=\["date"], dtype={"store":"string","sku":"string"})
g = df.groupby(\[df\["date"].dt.date, "store"]).agg(sales=("sales","sum"), qty=("qty","sum")).reset\_index().rename(columns={"date":"day"})
with pd.ExcelWriter(out\_xlsx, engine="xlsxwriter") as w:
g.to\_excel(w, sheet\_name="日次売上", index=False)
df.to\_excel(w, sheet\_name="明細", index=False)
return {"rows": int(len(df)), "groups": int(len(g))}

if **name** == "**main**":
ap = argparse.ArgumentParser()
ap.add\_argument("--src", type=Path, default=DEF\_IN)
ap.add\_argument("--out", type=Path, default=DEF\_OUT)
a = ap.parse\_args()
with FileLock(Path(".report.lock"), timeout=3):
info = build\_report(a.src, a.out)
log.info(f"report done rows={info\['rows']} groups={info\['groups']} out={a.out}")
print(info)

スケジュール:cron/Windowsタスクは[内部リンク:自動化]のテンプレ参照。仕上げの体裁は[内部リンク:データレポート納品の型]が便利です。

② 価格・在庫監視ボット(API/HTML→差分→通知)

要件例:可能ならAPI優先(なければ規約OKのHTML)。差分のみ通知、履歴はNDJSON/Parquetで保存。レート制限順守は必須。

設計ポイント:ETag等で差分取得、主キーで去重。429は停止、上限付きバックオフで再試行。

from __future__ import annotations
from pathlib import Path
import json, os, time
import requests
from utils import FileLock, log

BASE = "[https://api.example.com](https://api.example.com)"  # 実運用は環境変数で
API\_KEY = os.getenv("API\_KEY", "")
HEADERS = {"User-Agent":"pythonbunseki-monitor/1.0","Accept":"application/json","X-API-Key"\:API\_KEY}

HIST = Path("data/history.ndjson")
SEEN = set()  # 簡易(本番は過去ファイルを読む)

def fetch\_items() -> list\[dict]:
r = requests.get(f"{BASE}/items", headers=HEADERS, timeout=10)
if r.status\_code == 429:
raise RuntimeError("rate limited")
r.raise\_for\_status()
return r.json().get("items", \[])

def diff\_and\_notify(items: list\[dict]):
new = \[]
for it in items:
k = (it.get("id"), it.get("price"), it.get("stock"))
if k not in SEEN:
SEEN.add(k); new\.append(it)
if not new:
log.info("no changes"); return
\# 保存(NDJSON)
HIST.parent.mkdir(parents=True, exist\_ok=True)
with HIST.open("a", encoding="utf-8") as f:
for it in new:
f.write(json.dumps(it, ensure\_ascii=False) + "\n")
\# 通知(ダミー:標準出力)
for it in new\[:10]:
log.info(f"change id={it\['id']} price={it.get('price')} stock={it.get('stock')}")

if **name** == "**main**":
with FileLock(Path(".monitor.lock"), timeout=3):
tries = 0
while True:
try:
items = fetch\_items(); diff\_and\_notify(items); break
except (requests.Timeout, requests.ConnectionError) as e:
tries += 1
if tries >= 3: raise
wait = min(8, 0.5 \* 2 \*\* (tries-1))
log.warning(f"retry {tries} in {wait}s: {e}"); time.sleep(wait)

HTML版:[内部リンク:Webスクレイピング]のSession+Retry/robots.txt/セレクタテンプレを流用。保存形式の選び方は[内部リンク:ファイル操作]へ。

③ データ同期・バックアップ(CSV/SQLite/Parquet)

要件例:社内のCSV/SQLiteを日次スナップショットで保存し、backup/YYYYMMDD/*.parquetとして30世代保持。上書きせず、同日再実行でも同じ成果物。

設計ポイント:pandas → Parquetで圧縮・高速化。リテンションで古い世代を自動削除。

from pathlib import Path
import pandas as pd
from datetime import datetime
from utils import FileLock, log

SRC\_DIR = Path("data/source")
DST\_DIR = Path("backup")
KEEP = 30

def backup\_csvs():
today = datetime.now().strftime("%Y%m%d")
out = DST\_DIR/today; out.mkdir(parents=True, exist\_ok=True)
for p in sorted(SRC\_DIR.glob("*.csv")):
df = pd.read\_csv(p)
df.to\_parquet(out/(p.stem+".parquet"), compression="zstd")
\# 古い世代を削除
gens = sorted(\[d for d in DST\_DIR.iterdir() if d.is\_dir()])
for d in gens\[:-KEEP]:
for f in d.glob("\*\*/*"): f.unlink()
d.rmdir()
log.info(f"backup done dir={out} keep={KEEP}")

if **name** == "**main**":
with FileLock(Path(".backup.lock"), timeout=3):
backup\_csvs()

SQLiteの扱い:[内部リンク:SQLite×Python]のbackupAPIや.dump→Parquet化が堅実です。

運用チェックリスト(3ツール共通)

最低限、ここだけは通してください。

  • 再実行安全:タイムスタンプ依存を排し、同じ入力→同じ出力
  • 排他制御:ロック/キューで二重起動を防止
  • ログ:JSON Linesで時刻/レベル/件数/結果。ERROR/CRITICALは通知
  • 例外分類:外部(ネット/権限)/データ(パース)/業務ルールに分ける
  • 保存:原子置換・世代管理・PIIマスキング
  • レート制御:429/Retry-Afterを尊重。“人より遅い”アクセス
  • テスト:固定データでpytest最小セット → [内部リンク:単体テストpytest入門]
  • 配布:まずは[内部リンク:Docker超入門]で箱ごと。READMEに1コマンド起動を明記

よくあるユースケースと第一手

  • 営業の日報自動配信:ツール①+[内部リンク:データレポート納品の型]で表紙・注釈まで自動
  • ECの価格変動検知:ツール②+[内部リンク:API入門](なければ[内部リンク:Webスクレイピング])。429で停止を実装
  • 部門横断バックアップ:ツール③+[内部リンク:SQLite×Python]で毎晩スナップショット

今日やること(60分)

  1. 3ツールのうち1つを選び、requirements.txtとフォルダ(data/out//backup//logs/)を用意
  2. 本記事のテンプレコードを貼って手元データで動作確認
  3. cron/Windowsタスクで毎日1回回す
  4. JSONログを確認し、ERROR通知(ダミーでも可)を接続

まとめ:小さく作って、静かに強く回す

炎上ポイントは決まっています。だからこそ、idempotent+ロック+JSONログ+レート制御の“型”で作る。まずは定例レポート/価格監視/バックアップの3本から始めるのが近道です。

ポートフォリオ
実案件型ポートフォリオ:要件→実装→レポートの型|“業務再現”で採用担当に刺さる作り方

結論:採用担当が知りたいのは 「Kaggleのスコア」ではなく「現場で本当に回るか」。だからこそ、要件が言語化され、再現できる実装があり、最後は意思決定に直結するレポートで締める——この3点を1つの物 ...

自動化
自動化:スケジューリングと業務改善の型|「再実行安全×観測可能×静かに動く」を仕組みにする

夜中に動かしているPython、自動で止まってた…ログもなくて原因が追えない…。 「毎朝のレポート」や「在庫監視」を、壊れず静かに回したい…! 業務で落ちない自動化を作る鍵は、(1) 再実行安全(Id ...

例外処理
Python実務の型:例外処理と構造化ログでエラーに強いコードを書く

例外処理って、結局どこまでやれば“実務で困らない”の? ログも整えるのって大変そう…最低限の型、ください! この記事は、pythonbunseki.comの実務トーンで「防ぐ→気づく→復旧する」をコー ...

事故防止・効率化
もう事故らせない:PythonでCSV/JSON/Excelを安全に読み書きする実務レシピ

CSV/JSON/Excelの読み書き、どこから気をつければいい? 文字化け・先頭ゼロ欠落・壊れたExcel……もう事故らせたくない! 結論:データ仕事の9割はI/O(入出力)。ここを整えるだけで、桁 ...

Webスクレイピング
Webスクレイピング:requests×BeautifulSoupの基本|“合法×丁寧×再現性”でデータ取得を設計する

スクレイピングって、まず何から始めればいい? 禁止されていないか不安だし、アクセスのマナーや失敗しない実装も知りたい…! 結論は「合法性の確認 → 丁寧なアクセス → 再現性ある実装」の三位一体。本記 ...

API入門
API入門:OpenAPI/HTTPの基本と“壊れない”Pythonクライアント設計(コピペOK)

API連携を始めたいけど、何から学べば“壊れない仕組み”になる? OpenAPI?HTTP?タイムアウト?……用語が多すぎて迷子になりがち。 本記事は、HTTPの基礎×OpenAPIの読み方×堅牢なク ...

SQLite
【保存版】SQLite×Pythonで作る“ローカルDWH”——ETL・集計・レポート自動化の最短手順

ローカルでゼロ構築、ファイル1つで完結、サーバ不要。本記事はSQLite×Pythonで“毎日回る”ETL・集計・レポート自動化を最短で作るための完全ガイドです。データ設計→DB作成→ETL(取り込み ...

データレポート納品
【保存版】データレポート納品の型:要件定義→ETL→検証→可視化→Excel/PDF→引き継ぎまで、失注しないワークフロー完全版

“いい分析”より“伝わる納品”。副業や実務で評価されるのは、意思決定に効く1枚と再現できるパッケージを期限通り出せること。 本記事は、未経験〜初学者が週10時間×2〜3週で、要件定義→データ受領→ET ...

Docker
Docker超入門:学習環境を箱ごと保存する|“同じ環境が誰でも動く”を最小コストで実現

「同じコードなのに、相手のPCだと動かない…」——そのモヤモヤ、今日で終わらせましょう。 結論:学習や副業納品では、“環境を箱ごと固定”=Dockerが最強の近道です。再現性、衝突ゼロ、配布の簡単さを ...

Git/Github
【保存版】Git/GitHub入門:バージョン管理・ブランチ戦略・レビュー・自動化を“実務の型”で最短習得

「分析やノートブックは作れるけど、壊れない運用の“型”がない…」 「final_v3_fix2_LAST.xlsx地獄から抜け出して、レビューと自動化まで一気通貫で回したい!」 この記事では、未経験〜 ...

テスト
【コピペOK】pytestで“壊れないPython”を作る12ステップ

「昨日は動いてたのに、今日は壊れた…」 データ分析やETL、機械学習のコードで多発するこの悲劇。実は“テスト不在”が9割です。 本記事は、pytestで“壊れないPython”を作るための実務ガイド。 ...

伴走サポート:現場投入まで一緒に

要件整理→テンプレ適用→スケジュール→ログ/通知まで、初期導入を一緒に実施します。レビュー→改善の1サイクルで安定運用へ。

TechAcademy データサイエンスコース(受講料:174,600円~ ※更に割引あり)

TechAcademy 無料相談

株式会社キカガク AI人材長期育成コース(受講料:237,600円~)

キカガク 無料相談

この記事から次に読むべきもの

自動化
自動化:スケジューリングと業務改善の型|「再実行安全×観測可能×静かに動く」を仕組みにする

夜中に動かしているPython、自動で止まってた…ログもなくて原因が追えない…。 「毎朝のレポート」や「在庫監視」を、壊れず静かに回したい…! 業務で落ちない自動化を作る鍵は、(1) 再実行安全(Id ...

納品の型
データ可視化レポート納品の型:Tableau/Matplotlib|“図3点+結論1行+運用”で伝わる・続く・刺さる

結論:レポートは「データ→図」ではなく「意思決定→図」の順で設計します。最短で伝わり、運用で続く“型”は、(1) 結論1行、(2) 図3点(推移・分解・構成)、(3) 打ち手(閾値/費用対効果)、(4 ...

API入門
API入門:OpenAPI/HTTPの基本と“壊れない”Pythonクライアント設計(コピペOK)

API連携を始めたいけど、何から学べば“壊れない仕組み”になる? OpenAPI?HTTP?タイムアウト?……用語が多すぎて迷子になりがち。 本記事は、HTTPの基礎×OpenAPIの読み方×堅牢なク ...

Webスクレイピングの法的リスク
Webスクレイピングの法的リスクと安全運用|“規約→同意→頻度→記録”でトラブルを回避する実務ガイド

「副業や社内でスクレイピングを使いたい。でも、どこまでOKで、何をするとNG?」 結論、“安全運用の型”を最初に決めると迷いません。鍵は規約 → 同意 → 頻度 → 記録。 重要:本記事は一般情報です ...

SQLite
【保存版】SQLite×Pythonで作る“ローカルDWH”——ETL・集計・レポート自動化の最短手順

ローカルでゼロ構築、ファイル1つで完結、サーバ不要。本記事はSQLite×Pythonで“毎日回る”ETL・集計・レポート自動化を最短で作るための完全ガイドです。データ設計→DB作成→ETL(取り込み ...

最近のコメント

    • この記事を書いた人
    • 最新記事

    ふみと

    このブログでは、データサイエンティストとして市場価値を上げる方法を独自にまとめて発信しています。

    【プロフィール】
    ・大手企業データサイエンティスト/マーケティングサイエンティスト(10年、年収900万円台)/案件100件以上
    ・資格:JDLA E資格(日本ディープラーニング協会主催)/JDLA Community(CDLE会員)/Advanced Marketer/ビジネス統計スペシャリスト/統計検定2級/TOEIC 805
    ・スキル:Python/Tableau/SQL/機械学習/Deep Learning/RPA

    -実案件/ポートフォリオ