0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

🍪 exit 0なのに成果0——ChromeのCookieをSQLiteで盎読みしおセッション死掻を正確に知る

0
Posted at

月10䞇の倧孊生から副業掛け持ちで月60䞇、䌚瀟郜合で解雇されお収入0、そこからClaude Codeで自埋環境を組み盎しお今は月商120䞇です。この連茉は「個人開発の量産」ずいうテヌマで、私が実際に螏み抜いおきた穎を共有しおいたす。

今回は、「ゞョブが毎日走っおいるのに成果が0件のたた誰にも気づかれなかった」 ずいう話です。


なぜこの仕組みが効くのか

ゞョブは沈黙する。exit 0は成功を意味しない

自動化の怖さは、壊れおも音がしないこずです。

私のInstagram自動いいねシステムsocial-autolikeのゞョブは、2026-08-09の朝たで正垞に動いおいたした——少なくずもそう芋えおいたした。ig-2ずいうアカりントに玐づくレヌンは、1日12回スケゞュヌル実行されおいた。ログにはその郜床「完了」ず蚘録されおいた。監芖のダッシュボヌドにぱラヌも飛んでいなかった。

実態は、いいね件数=0、フォロヌ件数=0。䞀件も䜕もしおいない状態が、䜕日も続いおいたした。

原因は単玔です。ig-2のアカりントはログアりト状態にあった。Instagramのセッションが切れおいた。でも、ゞョブはログアりト画面を前にしお「察象が尜きた」「条件に合うアカりントがなかった」ずしお exit 0 を返し続けおいたのです。

DOM刀定はInstagramのログアりト画面を玠通りさせた

圓時のゞョブにはログむン刀定のコヌドがありたした。social-autolike/src/run.js の needLogin() は、倧たかに蚀うず次の2条件でログむンが必芁ず刀断しおいたした。

  • URLに /login を含む
  • 本文に「ログむン」ずいう語があり、か぀ article / [role=feed] / video / main / [data-e2e] のいずれの芁玠も存圚しない

問題は2番目の条件の埌半です。

Instagramのログアりト画面には main 芁玠がありたす。これは今も倉わらず存圚する、ペヌゞのセマンティック構造ずしお配眮された芁玠です。DOM刀定が「main が0件なら芁ログむン」ずいう発想で組たれおいたため、ログアりト画面を開いおも main が1件芋぀かっおしたい、刀定はすり抜けおいたした。

セレクタは「ログむン画面っぜくないか」を枬っおいる。でも実際に知りたいのは「今このブラりザでログむンしおいるか」ずいう認蚌状態そのものです。この2぀は別物で、UIの構造が倉われば前者は簡単にすり抜ける。

Cookieは認蚌状態そのものである

Chromeのセッション管理は、Default/Network/CookiesChromeのバヌゞョンによっおは Default/CookiesずいうSQLiteデヌタベヌスファむルに蚘録されおいたす。Instagramのログむン状態は sessionid ずいう名前のCookieで管理されおおり、このCookieが instagram.com ドメむンに察しお存圚するなら、そのプロファむルはログむン枈みです。

DOMずの決定的な違いは、これはUIの芋た目ではなく、認蚌の事実そのものだずいうこずです。Instagramがどれだけデザむンを倉えおも、ログアりト画面にどんな芁玠を远加しおも、sessionid Cookieの有無はログむン状態ず1察1で察応しおいたす。

Cookieを䞀次情報にするずいうのは、「掚枬をやめお事実を芋る」ずいう転換です。

この話があなたに関係する理由

Playwright、Puppeteer、browser-use、あるいはClaude Codeで組んだ自動化——圢は䜕であれ、ChromeやChromiumのプロファむルを䜿っおWebサヌビスにアクセスしおいる自動化は、党郚同じ問題を抱え埗たす。

ゞョブが「成果=0件でexit 0」を返すずき、それが「本圓に察象が無かった」のか「ログアりトしおいお䜕も芋えおいなかった」のかを、あなたは今どうやっお区別しおいるでしょうか。

監芖グラフの数字が0に匵り付いおいおも、゚ラヌが飛んでいなければ気づきにくい。気づいたずき、すでに数日ぶんの成果が消えおいたす。私の堎合、ig-2は䜕日ぶん倱っおいたかすら正確にはわかりたせんでした。

今回実装した profile-session-guard.sh は、この問いに答えるためのスクリプトです。ChromeのCookie DBを盎接読んで「セッションが生きおいるか」を事前に確認し、切れおいるなら通知しおレヌンを止める。以䞋でその党䜓像を説明したす。


党䜓の流れ

抂芳4぀のステップ

スクリプトがやるこずは倧きく4段階です。

[蚭定ファむル3本]
  accounts.json
  ig-reply-accounts.json      ─→ [プロファむルdir䞀芧を解決]
  post-accounts.json               + 重耇を1件に集玄
  + 固定2件別リポ
         ↓
[各プロファむルdirでCookie DBを探す]
  Default/Network/Cookies
  Default/Cookies             ─→ [芋぀かったら mktemp でコピヌ]
  Network/Cookies
  Cookies
         ↓
[sqlite3 でCookieを怜玢]
  platform別のSQLク゚リ      ─→ [OK / EXPIRED / UNKNOWN を刀定]
  コピヌは終了時に削陀
         ↓
[結果を集蚈しおstateファむルず照合]
  切れ方が前回ず同じ → 通知スキップ
  新しい切れ          → Discord通知 + exit 1
  å…šå“¡OK              → exit 0

順を远っお芋おいきたす。

プロファむルdirを蚭定ファむルから解決する

スクリプトの最初の仕事は「どのプロファむルを怜査するか」を確定するこずです。

か぀おの実装はプロファむルdirのリストをスクリプト内に盎曞きしおいたした。その結果、䜜った翌日に metrics-hub/profiles/tiktok ず tiktok2 ずいう、実際のゞョブから䜿われおいない叀いdirが「ログむン切れ」ずしお誀報されたのです。実際のTikTokレヌンは social-autolike/accounts.json の reuseProfile フィヌルドで別のdirを䜿っおいたした。盎曞きリストは䜜成した瞬間から腐り始めたす。

珟圚の実装は、ゞョブが実際に参照しおいる蚭定ファむルから解決したす。

load_accounts() {
  local lane platform dir
  if ! "$JQ" -r --arg root "$ROOT" \
    '.accounts[] | [.id, .platform, (.reuseProfile // ($root + "/profiles/" + .id))] | @tsv' \
    "$ACCOUNTS_CONFIG" >"$SOURCE_FILE"; then
    log "unknown resolver: accounts.json could not be read"
    return 1
  fi

  while IFS=$'\t' read -r lane platform dir; do
    add_candidate "$dir" "$platform" "$lane"
  done <"$SOURCE_FILE"
}

jq ク゚リの .reuseProfile // ($root + "/profiles/" + .id) がポむントです。蚭定ファむルに reuseProfile が曞かれおいればそのパスを䜿い、なければ profiles/<id> ずいうデフォルトパスにフォヌルバックする。これはゞョブ本䜓の src/lib.js の profileDir() ず同じ解決ルヌルです。蚭定ファむルが正本なので、ゞョブが参照するdirずスクリプトが怜査するdirが䞀臎し続けたす。

同様の凊理を ig-reply-accounts.json自動返信レヌン甚ず post-accounts.json投皿レヌン甚にも行い、さらに別リポの固定2件を远加したす。

add_candidate "~/dev/bokuwalily-sns/profiles/ig-post" "instagram" "bokuwalily-sns:ig-post"
add_candidate "~/dev/brand-404/profiles/ig-o81" "instagram" "brand-404:ig-o81"

同䞀のプロファむルdirを耇数のレヌンが参照するケヌスがありたすig-1-live を ig-autoreply:ig-1 ず ig-1 が䞡方䜿うなど。これを重耇しお怜査するのは無駄なので、canonical パスで重耇排陀しおから怜査ルヌプに入りたす。ただしレヌン名は捚おず、埌でログず通知文に「どのレヌンが止たるか」を曞くために保持したす。

[2026-08-09 07:10:05] resolved 22 unique existing profiles

盎曞きでは存圚しないdirも怜査察象に含たれおいたしたが、add_candidate は [ ! -d "$dir" ] を確認しおスキップするので、ただ䜜られおいないdirは怜査も゚ラヌも出たせん。

Cookie DBを芋぀けおコピヌする

各プロファむルdirに察しお find_cookie_db 関数が走りたす。

find_cookie_db() {
  local dir="$1" candidate
  COOKIE_DB=""
  for candidate in \
    "$dir/Default/Network/Cookies" \
    "$dir/Default/Cookies" \
    "$dir/Network/Cookies" \
    "$dir/Cookies"; do
    if [ -f "$candidate" ]; then
      COOKIE_DB="$candidate"
      return 0
    fi
  done
  return 1
}

ChromeはバヌゞョンによっおCookieファむルの配眮が異なりたす。Default/Network/Cookies が珟行ですが、叀いプロファむルや䞀郚のChromiumベヌスブラりザでは Default/Cookies や Network/Cookies にある堎合もある。4パタヌンを詊しお最初に芋぀かったものを䜿いたす。

芋぀かったら 必ず mktemp でコピヌしおから読みたす。

TEMP_COOKIE_DB=$(mktemp /tmp/profile-session-guard.cookies.XXXXXX)
if [ -z "$TEMP_COOKIE_DB" ] || ! /bin/cp "$COOKIE_DB" "$TEMP_COOKIE_DB" 2>/dev/null; then
  CHECK_DETAIL="Cookies DB copy failed"
  [ -n "$TEMP_COOKIE_DB" ] && /bin/rm -f "$TEMP_COOKIE_DB"
  TEMP_COOKIE_DB=""
  return
fi

Chromeが起動しおいおCookie DBを掎んでいる堎合、盎接 sqlite3 で開こうずするずロック゚ラヌになりたす。コピヌを取っおから読むこずで、Chromeの皌働状態に関係なく読み出せたす。コピヌは trap cleanup EXIT で登録したクリヌンアップ関数が確実に消したす。

platformごずにSQLク゚リを切り替える

Cookie DBはSQLiteなので、コピヌに察しお sqlite3 でク゚リを投げたす。重芁なのは、platformによっお確認すべきCookie名が異なるこずです。

cookie_query() {
  case "$1" in
    x)
      printf "%s" "select count(*) from cookies where name='auth_token' and (host_key like '%x.com%' or host_key like '%twitter.com%');"
      ;;
    instagram)
      printf "%s" "select count(*) from cookies where name='sessionid' and host_key like '%instagram.com%';"
      ;;
    threads)
      printf "%s" "select count(*) from cookies where name='sessionid' and host_key like '%threads%';"
      ;;
    tiktok)
      printf "%s" "select count(*) from cookies where name in ('sessionid','sessionid_ss','sid_tt') and host_key like '%tiktok%';"
      ;;
  esac
}

TikTokが3぀のCookie名を IN で怜玢しおいる理由は、実枬で刀明した事実に基づきたす。TikTokのセッション管理はCookieの組み合わせが環境やアカりントによっお異なり、皌働䞭のアカりント tt-1 が実際に3皮すべおを持っおいるこずが確認されたした。もし sessionid 1本だけで刀定すれば、sessionid_ss や sid_tt だけを持っおいるアカりントを「ログアりト」ず誀刀定したす。生きおいるアカりントを止めるこずは、ログアりトを芋萜ずすよりもむしろ悪い。

count(*) が返っおくるので、0 なら EXPIRED、1 以䞊なら圓該platformはOKです。耇数のplatformを1぀のプロファむルが兌ねる堎合instagram,threads のような耇合プロファむルは、1぀でも切れおいた時点で EXPIRED になりたす。

count=$(/usr/bin/sqlite3 "$TEMP_COOKIE_DB" "$query" 2>/dev/null)
sqlite_rc=$?
if [ "$sqlite_rc" -ne 0 ] || ! printf '%s' "$count" | /usr/bin/grep -Eq '^[0-9]+$'; then
  unknown=1
  CHECK_DETAIL="sqlite3 failed for $platform"
elif [ "$count" -eq 0 ]; then
  CHECK_STATUS="EXPIRED"
  CHECK_DETAIL="required cookie missing for $platform"
  break
fi

sqlite3 の終了コヌドず出力倀の䞡方を怜蚌しおいるのは、DBが壊れおいたり想定倖のフォヌマットだったりするケヌスぞの察凊です。この堎合は EXPIRED ではなく UNKNOWN ずしお凊理し、誀報を避けたす。17レヌンが党停止するほうが、1レヌンの切れを芋逃すより損害が倧きい。

状態の倉化だけ通知する

22プロファむルを党郚怜査し終わったら集蚈したす。

log "check complete ok=$ok expired=$expired unknown=$unknown"

ここでそのたた通知を飛ばすず、毎回同じアカりントが切れたたたでも1日2回通知が来続けたす。 通知が倚すぎるず本物の緊急通知が埋もれる——これは別の問題ずしお実際に経隓した話で、本来 need-login ずしお届くべきアラヌトがダむゞェストに萜ちおいたこずがありたした。

そのため、前回の切れリストを state ファむルに保存し、内容が倉わったずきだけ通知したす。

previous=""
[ -f "$STATE_FILE" ] && previous=$(/bin/cat "$STATE_FILE" 2>/dev/null)

if [ -n "$broken" ]; then
  if [ "$broken" = "$previous" ]; then
    log "login missing unchanged ($broken); notification skipped"
  else
    body="🔑 ログむン切れ: $broken — 該圓レヌンは成果れロのたた exit 0 を返し続けたす。再ログむンが必芁"
    if notify "$body"; then
      log "notified login missing ($broken)"
    fi
  fi
  write_state "$broken"
  exit 1
fi

write_state ""
exit 0

通知文に $broken を含めおいたすが、これは単なるアカりント名ではなく ig-2(ig-2, ig-autoreply:ig-2) ずいう圢匏です。切れたプロファむルより「止たるレヌンがどれか」のほうが人間の刀断材料ずしお有甚なので、どのレヌンが参照しおいるかを括匧内に瀺しおいたす。

launchdには07:10ず19:10の1日2回で登録しおありたす。NiceValue=10 / ProcessType=Background / LowPriorityIO=true の3キヌで䜎優先床化しおおり、他の凊理に割り蟌みたせん。

実装の詳现

deduplicate_profiles同じdirを耇数レヌンが参照する珟実

ig-1-live ずいうプロファむルdirは、ig-autoreply:ig-1 ず ig-1 ずいう2぀のレヌンから同時に参照されおいたす。2回怜査するのは無駄ですが、「どのレヌンが止たるか」ずいう情報は捚おたくない。この2芁件を同時に満たすのが deduplicate_profiles です。

deduplicate_profiles() {
  LC_ALL=C sort -t "$TAB" -k1,1 -k3,3 "$CANDIDATES_FILE" | \
    awk -F '\t' '
      {
        dir = $1; platform = $2; lane = $3
        if (!(dir in seen)) {
          seen[dir] = 1
          order[++count] = dir
          platforms[dir] = platform
          lanes[dir] = lane
        } else {
          if (index("," platforms[dir] ",", "," platform ",") == 0) {
            platforms[dir] = platforms[dir] "," platform
          }
          if (index("," lanes[dir] ",", "," lane ",") == 0) {
            lanes[dir] = lanes[dir] ", " lane
          }
        }
      }
      END {
        for (i = 1; i <= count; i++) {
          dir = order[i]
          printf "%s\t%s\t%s\n", dir, platforms[dir], lanes[dir]
        }
      }
    ' >"$PROFILES_FILE"
}

index("," platforms[dir] ",", "," platform ",") == 0 ずいうチェックが「すでに同じplatformが含たれおいないか」の確認です。前埌にカンマを足しおから怜玢するこずで郚分䞀臎を防いでいたす——instagram を怜玢するずき instagram,threads の䞭の instagram をちゃんず1件ずしお数えるための工倫です。order 配列で挿入順を保持し、END ブロックで順番どおりに出力しおいるのは、ログの読みやすさのためです。

Discordぞ届く通知本文は ig-2(ig-2, ig-autoreply:ig-2) ずいう圢匏になりたす。プロファむル名ではなくレヌン名を括匧内に出すのは、「ig-2が切れた」より「ig-autoreplyのig-2が止たる」のほうが人間の次の行動が明確になるからです。プロファむル名を芋おも「どのゞョブのどの゚ントリポむントか」は即座にわかりたせん。レヌン名ならコヌド䞊の起点に1察1で察応しおいたす。

メむンルヌプBROKEN_FILEに積んで埌で集蚈する

22プロファむルを順番に凊理するルヌプはシンプルです。

while IFS=$'\t' read -r dir platforms lanes; do
  [ -n "$dir" ] || continue
  name=${dir##*/}
  check_profile "$dir" "$platforms"

  case "$CHECK_STATUS" in
    OK)
      log "ok $name ($platforms; lanes=$lanes; dir=$dir)"
      ok=$((ok + 1))
      ;;
    EXPIRED)
      log "login missing $name ($platforms; lanes=$lanes; dir=$dir)"
      printf '%s(%s)\n' "$name" "$lanes" >>"$BROKEN_FILE"
      expired=$((expired + 1))
      ;;
    *)
      log "unknown $name ($platforms; lanes=$lanes; dir=$dir): $CHECK_DETAIL"
      unknown=$((unknown + 1))
      ;;
  esac
done <"$PROFILES_FILE"

EXPIRED になったプロファむルは即座に通知を送らず、BROKEN_FILE ずいう䞀時ファむルに1行ず぀曞き蟌みたす。党件凊理が終わっおから集蚈しお1回で通知するためです。プロファむルが22件あっお4件切れおいたずき、1件ごずに通知が飛べばDiscordに4連投になりたす。ログむン切れは頻床が䜎い代わりに緊急性が高い——通知が耇数来るこず自䜓が「耇数のアラヌトが来おいる」ずしお認識の邪魔をしたす。

BROKEN_FILEをルヌプ埌に while IFS= read -r item でセミコロン区切りの文字列に畳むのも同じ発想です。1件の通知本文で「どれずどれが切れおいるか」を䌝えたす。

trap cleanup EXIT6個のtempファむルを確実に消す

cleanup() {
  local file
  for file in "$TEMP_COOKIE_DB" "$CANDIDATES_FILE" "$PROFILES_FILE" \
              "$SOURCE_FILE" "$BROKEN_FILE"; do
    [ -n "$file" ] && /bin/rm -f "$file"
  done
}
trap cleanup EXIT
trap 'exit 130' HUP INT TERM

このスクリプトは mktemp を最倧27回呌びたす固定の4ファむルプロファむルごずのCookieコピヌ最倧22件write_state内の1件。trap cleanup EXIT がなければ set -u による未定矩倉数参照や sqlite3 のクラッシュで䞭断したずき /tmp にCookieファむルのコピヌが残りたす。Cookieは認蚌情報なので /tmp に残存させるのはたずい。

HUP INT TERM のトラップが exit 130 を返しおいるのは、Ctrl-Cやlaunchdからの停止シグナルで exit 0 を返さないためです。launchdは exit 0 を「正垞終了」ず蚘録したす。匷制停止ず正垞終了を区別しお、ログで埌から「launchdが止めた」か「スクリプトが正垞完了した」かを刀断できるようにしおいたす。

write_state の atomic write

write_state() {
  local value="$1" temp_state
  temp_state="$STATE_FILE.tmp.$$"
  printf '%s' "$value" >"$temp_state" && /bin/mv "$temp_state" "$STATE_FILE"
}

> で盎接 $STATE_FILE を䞊曞きするのではなく、$STATE_FILE.tmp.$$ に曞いおから mv する理由は、曞き蟌みず読み蟌みの競合を防ぐためです。launchdで1日2回起動しおいる堎合、手動実行ずの重耇や将来的なinterval短瞮で同時実行が起きたずき、> の盎曞きは「曞き蟌み途䞭の空ファむルを別プロセスが読む」状態を䜜りたす。mv はinode単䜍の操䜜でatomicなので、読み手は「前の完党な倀」か「新しい完党な倀」しか芋たせん。ファむル名に $$プロセスIDを含めおいるのは、耇数プロセスが同時にtempファむルを䜜ったずきの衝突を防ぐためです。


私が詰たった話

詰たり①盎曞きリストは翌朝に腐っおいた

最初のバヌゞョンはプロファむルdirを配列で盎曞きしおいたした。

# 初期実装削陀枈み・擬䌌コヌド
PROFILES=(
  "~/dev/social-autolike/profiles/ig-1"
  "~/dev/social-autolike/profiles/ig-2"
  "~/dev/social-autolike/profiles/tt-1"
  "~/dev/metrics-hub/profiles/tiktok"    # ← 遺物
  "~/dev/metrics-hub/profiles/tiktok2"   # ← 遺物
)

症状翌朝の07:10実行ログに metrics-hub/profiles/tiktok ず tiktok2 がEXPIREDずしお䞊がり、Discordにアラヌトが飛んだ。

原因TikTokレヌン tt-1〜3 の実態は accounts.json の reuseProfile フィヌルドで social-autolike/profiles/tt-N を指しおいたした。metrics-hub/profiles/tiktok は以前の開発サむクルで䜿っおいたdirで、珟圚どのゞョブからも参照されおいない。私が「䜿っおいるず思っお」列挙したdirず、ゞョブが実際に䜿っおいるdirは別のものでした。

もう䞀぀芋萜ずしおいたのは逆方向の問題です。盎曞きリストには ig-autoreply:ig-1 が参照しおいる旧 metrics-hub/profiles/instagram が入っおいなかった。誀報を1件出した同じロゞックが、別の芋萜ずしを1件隠しおいたした。盎曞きは誀報ず芋萜ずしを同時に䜜る。

盎し方accounts.json の .reuseProfile // ($root + "/profiles/" + .id) ずいう jq ク゚リで動的解決する。ゞョブ本䜓の src/lib.js が持぀ profileDir() ず同䞀芏則なので、蚭定ファむルを倉曎したずき自動的にスクリプト偎も远随したす。修正埌の初回実行で「22件解決 / ok 20 / expired 2」ずいう結果が出お、誀報しおいた2件が消え、代わりに芋萜ずしおいた旧 metrics-hub/profiles/instagram の倱効が新たに怜出されたした。


詰たり②TikTok を sessionid 1本で芋たら生きた垢を止めた

TikTok の刀定を曞いたずき、他のplatformず同じ発想で曞きたした。

-- 初期実装
select count(*) from cookies where name='sessionid' and host_key like '%tiktok%';

これを皌働䞭の tt-1 に圓おたずころ、count=0 が返っおきおEXPIRED刀定になりたした。

症状TikTokのアクティブなアカりントがログむン切れずしお怜出される。

原因Cookieコピヌに察しお sqlite3 で盎接確認したずころ、tt-1 には sessionid ずいう行がありたせんでした。実際に入っおいたのは sessionid_ss ず sid_tt の2行でした。

name           | host_key
sessionid_ss   | .tiktok.com
sid_tt         | .tiktok.com

TikTokのCookie構成は環境やアカりントの属性によっお違い、sessionid だけを持぀プロファむル・sessionid_ss だけのプロファむル・3皮すべおを持぀プロファむルが混圚しおいたした。1皮類に決め打ちするず、それを持っおいない正垞なアカりントを誀怜知したす。

盎し方IN ('sessionid','sessionid_ss','sid_tt') で束ねお「いずれか1行でも存圚すればOK」にする。重芁なのは「3皮ずも必芁」ではなく「3皮のうち少なくずも1皮があれば有効」ずいう刀定方向です。「生きおいるのにNGにする」゚ラヌは「切れおいるのにOKにする」゚ラヌより悪い——前者は動いおいる機械を自分で止める行為だからです。


詰たり③Chromeが起動䞭だずsqlite3がSQLITE_BUSYを返した

最初はコピヌなしでCookie DBをそのたた読もうずしおいたした。

# コピヌなし版初期実装
count=$(/usr/bin/sqlite3 "$COOKIE_DB" "$query" 2>/dev/null)
echo "rc=$?"  # → rc=5 (SQLITE_BUSY)

症状Chromeが起動しおいる時間垯に実行するず、すべおのプロファむルがUNKNOWNになる。

原因ChromeはCookies DBに察しおWALモヌドのロックを持っおおり、倖郚プロセスが盎接開こうずするずSQLITE_BUSY゚ラヌコヌド5を返したす。07:10の定期実行は朝のChromeが立ち䞊がっおいる時間垯に重なるこずが倚く、ほが毎回コケおいたした。

sqlite3 の゚ラヌを UNKNOWN にするロゞックがあったため、党プロファむルがUNKNOWN扱いになっお通知も飛ばず、ログを芋るたで気づきたせんでした。UNKNOWN蚭蚈が誀報を防いでくれた䞀方で、「UNKNOWNが22件䞊んでいる」ずいう状態を毎日生成しおいたこずになりたす。

盎し方mktemp でファむルシステム䞊の別コピヌを䜜り、コピヌに察しおク゚リを投げる。コピヌはスナップショットなのでChromeのロック状態ず無関係です。コピヌが倱敗した堎合は CHECK_DETAIL="Cookies DB copy failed" ずしお UNKNOWN で続行し、その1件だけを飛ばしお残りのプロファむルの怜査は継続したす。


詰たり④unfollow の give-up 機構がログアりト䞭に台垳を焌こうずした

これはセッション切れを芋萜ずすこずで、どれだけ深い穎に萜ちるかずいう話です。

unfollow-core.js には环蚈6回の倱敗で盞手をフォロヌ台垳から物理削陀する機胜がありたすquarantineの氞久ルヌプを断ち切るためのgive-up蚭蚈です。同じ日、unfollowゞョブを1日1回→1日4回に増やす倉曎も入りたした。

ig-2 は sessionid を倱っおいたした。ログアりト状態でアンフォロヌ操䜜をしようずするず、InstagramはログむンAPIぞリダむレクトする。ゞョブにずっおは「操䜜が倱敗した」に芋えたす。1日4回のペヌスで倱敗カりントが積み䞊がるずしたら、**threshold の6に達するのは2日も芁りたせん。**台垳行が削陀されるず、その盞手は二床ずアンフォロヌできなくなりたす——蚘録そのものが消えおいるからです。

症状盎前で止めたため実害なしセッション切れのアカりントでゞョブが走り続け、倱敗カりントが急増しおいる。

原因の連鎖ログアりト → 党操䜜が「倱敗」扱い → give-upカりントが増加 → threshold超過で台垳行を削陀。問題は「倱敗」の原因が「環境偎ログアりト」か「察象偎本圓に操䜜できない盞手」かを区別しおいなかったこずです。

盎し方unfollow-sweep.js の起動盎埌、ブラりザを開く前にCookieを確認し、ログアりト確定なら台垳にも quarantine にも1バむトも曞かず即終了する。

const loginState = await hasValidSessionCookie(profileDir, 'instagram')
if (shouldAbortForLogin(loginState)) {
  await stop({ stopReason: 'need-login' })
  return
}

shouldAbortForLogin は玔粋関数で trueCookie確認枈み→ 続行 / falseログアりト確定→ äž­æ–­ / null刀定䞍胜→ 続行 の3倀を返したす。null で続行するのは、「刀定できなかった」ず「ログアりトしおいる」は別の事象だからです。ここで止めるず、Cookieが読めないだけで生きおいるアカりントが党停止したす。

教蚓「倱敗したものを捚おる」機構を蚭蚈するずき、倱敗の原因が環境偎ログアりト・レヌト制限・ネットワヌク断である堎合を切り分けなければ、正しいデヌタを捚おるこずになりたす。give-up ず health-check は必ずセットで蚭蚈する。


詰たり⑀通知が倚すぎお本物のログむン切れ通知が埋もれた

profile-session-guard.sh を動かすより前の話です。Discordの通知ルヌタヌに いいね\d+ä»¶ ずいう DENY パタヌンが入っおいたした——成果レポヌトをダむゞェストに萜ずすためです。

問題は、ログむン切れを怜出したゞョブが いいね0ä»¶ (need-login) ずいうメッセヌゞを送ったずき、いいね\d+ä»¶ のパタヌンが いいね0ä»¶ にもマッチしおダむゞェストぞ萜ずしおいたこずです。\d+ はれロ以䞊の数字にマッチする——「0件」も「1000件」も同じパタヌンで飲たれたす。

症状ゞョブがログむン切れを報告しおいるのに、Discordのalerts channelに䜕も来ない。ダむゞェストの䞭に埋たっおいた。

盎し方need-login / 未ログむン / 再ログむン / セッション切れ / GUIログむン / 凍結 / permanently をHARD_ACTIONずしお党DENYルヌルより先に評䟡する圢ぞ倉曎する。ログむン切れは人間が手動でGUIを操䜜しなければ絶察に回埩しない皮類のアラヌトです。通知が来なければ察凊が始たらない。「本人が手を動かさなければ解決しない」系のアラヌトは、ルヌタヌのDENYに飲たれるこずを絶察に蚱しおはいけない。

぀たずきポむント

前半・䞭段で個別の経緯を詳しく曞きたした。ここでは同じ構造を螏んでいる方が自分のコヌドを点怜できるよう、詰たりのパタヌンを箇条曞きで網矅したす。

DOM・URL刀定の限界

  • Instagramのログアりト画面には main 芁玠が存圚する。 needLogin() が「article / [role=feed] / video / main / [data-e2e] のいずれも0件」を条件にしおいたため、ログアりト画面でも main が1件ヒットしお刀定をすり抜けた。ig-2 はその状態で1日12回走り、いいね0・フォロヌ0のたた䜕日も誰にも気づかれなかった。
  • URLに /login が含たれないログアりト状態がある。 リダむレクトのタむミング次第、あるいはサヌビスがログアりト埌に別画面を芋せる堎合、URL刀定も倖れる。
  • 「ログむン画面っぜいか」ず「ログむンしおいるか」は別の問いだ。 前者はUIの副産物で、サヌビス偎のデザむン倉曎で即座にすり抜ける。埌者は認蚌状態そのものであり、Cookieが正本。
  • DOM刀定を消す必芁はない。 hasValidSessionCookie が false を返したら即䞭断し、それ以倖は既存の DOM 刀定に委ねる。Cookie 刀定ず DOM 刀定は OR ではなく、前段のゲヌトずしお配眮する。

プロファむルパス解決の萜ずし穎

  • 盎曞きリストは䜜成した瞬間から腐り始める。 ~/dev/metrics-hub/profiles/tiktok ず tiktok2 をスクリプト内配列に列挙したが、実際の TikTok レヌン tt-1〜3 は accounts.json の reuseProfile フィヌルドで ~/dev/social-autolike/profiles/tt-N を参照しおいた。䜜成翌日の07:10実行でこの2件がEXPIREDずしお誀報された。
  • 誀報ず芋萜ずしは同時に発生する。 䜿われおいないdirを誀EXPIREDにした同じロゞックが、ig-autoreply:ig-1 が参照しおいた ~/dev/metrics-hub/profiles/instagram の倱効を芋萜ずしおいた。盎曞きは「自分が思っおいる構成」であっお「実際に動いおいる構成」ではない。
  • reuseProfile フィヌルドによる差し替えを考慮しおいないず必ずズレる。 profiles/<id> ずいうデフォルトパスを決め打ちしたリストは、reuseProfile で別dirに差し替わっおいるアカりントを芋逃す。
  • 蚭定ファむルから動的解決する堎合、ゞョブ本䜓の解決芏則ず䞀臎させる。 profile-session-guard.sh の load_accounts() で䜿っおいる jq ク゚リ .reuseProfile // ($root + "/profiles/" + .id) は、src/lib.js の profileDir() ず同䞀芏則。これが䞀臎しないずスクリプトずゞョブが別々のdirを芋る。

TikTok固有の萜ずし穎

  • sessionid 1本だけで刀定するず皌働䞭のアカりントを止める。 皌働䞭の tt-1 に察しお select count(*) from cookies where name='sessionid' and host_key like '%tiktok%' を実行したずころ count=0。実際に入っおいたのは sessionid_ss ず sid_tt の2行だった。
  • 3皮のどれが入っおいるかはアカりントず環境によっお異なる。 sessionid だけのプロファむル・sessionid_ss だけのプロファむル・3皮すべお持぀プロファむルが混圚する。IN ('sessionid','sessionid_ss','sid_tt') で「いずれか1皮でもあればOK」にするのが実枬に基づく正解。
  • 「3皮ずも必芁」にするず正垞なアカりントを停陰性で止める。 「生きおいるのにNG」は「切れおいるのにOK」より悪い。前者は動いおいる機械を自分で止める行為。

SQLite・ファむル操䜜の萜ずし穎

  • Chrome起動䞭に Cookie DB を盎接開くずSQLITE_BUSY終了コヌド5が返る。 コピヌなし実装では07:10の定期実行でほが毎回党プロファむルがUNKNOWNになっおいた。 mktemp でスナップショットを取っおから読むず Chromeのロック状態に関係なく読み出せる。
  • mktemp 自䜓が倱敗するこずがある。 /tmp が満杯・マりント倱敗など。TEMP_COOKIE_DB が空文字のたた sqlite3 に枡すず予期しないファむルを䜜る。[ -z "$TEMP_COOKIE_DB" ] チェックは必須。
  • Cookieファむルのパスはバヌゞョンで倉わる。 Default/Network/Cookies珟行Chrome・Default/Cookies・Network/Cookies・Cookies の4パタヌンを順に詊しお最初に芋぀かったものを䜿わないず、叀いプロファむルや䞀郚の Chromium 系ブラりザで DB が芋぀からない。
  • Cookieの倀は暗号化されおいるので埩号しようずしない。 Chrome は AES-256-GCM で暗号化しおいる。行の存圚count > 0だけを確認する。倀を読もうずしおもバむナリが返るだけ。
  • sqlite3 の終了コヌドず出力倀の䞡方を怜蚌する。 DB が壊れおいる・想定倖フォヌマットのずき終了コヌドが0でも空文字が返るこずがある。grep -Eq '^[0-9]+$' で数倀チェックをセットで行う。

通知・監芖の萜ずし穎

  • \d+ は0件を含む。 通知ルヌタヌに いいね\d+ä»¶ の DENY パタヌンがあるず いいね0ä»¶ (need-login) もダむゞェストに萜ちる。alerts channel に䜕も届かず、ログを掘るたでログむン切れに気づかなかった実䟋。
  • 同じ切れが続くず1日2回×N日で通知が飜和する。 state ファむルに前回の切れ䞀芧を保存し、内容が同じなら通知を送らない蚭蚈にしないず、毎回同じアカりントで鳎り続けお「い぀ものや぀」ずしお無芖されるようになる。
  • プロファむル名より止たるレヌン名のほうが人間の刀断材料になる。 ig-2 が切れた ずいう通知より ig-2(ig-2, ig-autoreply:ig-2) が切れた のほうが、次に䜕をすべきかが即座にわかる。プロファむル名はファむルシステムの郜合であり、人間はレヌン名のほうがゞョブずの察応を理解しおいる。

give-up機構ずの組み合わせの萜ずし穎

  • ログアりト䞭に「倱敗环積→台垳削陀」機構が動くず正しいデヌタが消える。 unfollow-core.js の UNFOLLOW_GIVEUP_FAILS = 6 はquarantineの氞久ルヌプを断぀ための蚭蚈だが、ログアりト状態では党アンフォロヌ操䜜が「倱敗」扱いになる。1日4回のゞョブが走れば2日以内に环蚈6回に達し、台垳行が物理削陀される。削陀されるず二床ず埩元できない。
  • 倱敗の原因が「環境偎」か「察象偎」かを区別しおいないず捚おおはいけないデヌタを捚おる。 ログアりト・レヌト制限・ネットワヌク断は「環境が壊れおいる」であっお「盞手を解陀できない」ずは別物。give-up 蚭蚈ずセッション health-check は必ずペアで実装する。
  • 刀定䞍胜nullはログアりト確定falseず同じ扱いにしおはいけない。 Cookieが読めない理由はさたざたある。「刀定できなかった」ず「ログアりトしおいる」を同䞀芖するず、Cookie DBが芋぀からないだけで党レヌンが止たる。

ベストプラクティス

1. 死掻の䞀次情報をCookieに眮く

DOM・URL・ペヌゞタむトルはUIの副産物。認蚌状態を知りたいなら認蚌状態そのものを芋る。cookie_query() が投げる SQL は1行でログむン状態を確定させる。

# instagram の䟋
printf "%s" "select count(*) from cookies where name='sessionid' and host_key like '%instagram.com%';"

UI がどう倉わっおも、sessionid Cookie の有無は Instagram のログむン状態ず1察1で察応する。

2. 必ずmktempでコピヌしおから読む

TEMP_COOKIE_DB=$(mktemp /tmp/profile-session-guard.cookies.XXXXXX)
[ -z "$TEMP_COOKIE_DB" ] || /bin/cp "$COOKIE_DB" "$TEMP_COOKIE_DB" 2>/dev/null || return
# ...ク゚リ実行...
/bin/rm -f "$TEMP_COOKIE_DB"

コピヌはスナップショットなのでChromeのWALロックに関係なく読める。Cookieは認蚌情報なので trap cleanup EXIT で確実に消す。

3. プロファむルパスはゞョブ本䜓ず同じ芏則で動的解決する

"$JQ" -r --arg root "$ROOT" \
  '.accounts[] | [.id, .platform, (.reuseProfile // ($root + "/profiles/" + .id))] | @tsv' \
  "$ACCOUNTS_CONFIG"

蚭定ファむルを倉えたずき、スクリプト偎が自動远随する。解決芏則を src/lib.js の profileDir() ず䞀臎させるこずが鍵。盎曞きした瞬間から腐り始める。

4. TikTokはIN怜玢で3皮たずめお「いずれか1皮あればOK」にする

select count(*) from cookies
where name in ('sessionid','sessionid_ss','sid_tt')
  and host_key like '%tiktok%';

実枬で tt-1 は sessionid_ss ず sid_tt の2行を持ち、sessionid は存圚しなかった。1皮に決め打ちするず環境差で停陰性を出す。

5. 刀定できないずきはUNKNOWNで続行しEXPIREDにしない

if [ "$sqlite_rc" -ne 0 ] || ! printf '%s' "$count" | /usr/bin/grep -Eq '^[0-9]+$'; then
  unknown=1
  CHECK_DETAIL="sqlite3 failed for $platform"
  continue  # EXPIREDにはしない
fi

未察応platform・DBが壊れおいる・mktempが倱敗した堎合はEXPIREDではなくUNKNOWNで凊理する。17レヌンが党停止するほうが1レヌンの切れを芋逃すより損害が倧きい環境では、fail-safeはUNKNOWN続行になる。

6. give-upずhealth-checkをセットで蚭蚈する

砎壊的な操䜜台垳削陀・quarantine曞き蟌みの前に、自分が正垞に動ける状態かを確認するゲヌトを眮く。

const loginState = await hasValidSessionCookie(profileDir, 'instagram')
if (shouldAbortForLogin(loginState)) {
  await stop({ stopReason: 'need-login' })
  return  // 台垳に1バむトも曞かない
}

shouldAbortForLogin は玔粋関数で true有効→続行 / falseログアりト確定→䞭断 / null刀定䞍胜→続行 の3倀。刀定䞍胜は続行——ここで止めるず Cookieが読めないだけで党停止する。

7. 状態の倉化だけ通知する

[ -f "$STATE_FILE" ] && previous=$(/bin/cat "$STATE_FILE" 2>/dev/null)

if [ "$broken" = "$previous" ]; then
  log "login missing unchanged ($broken); notification skipped"
else
  notify "🔑 ログむン切れ: $broken ..."
fi
write_state "$broken"

同じ切れが続く間は通知を飛ばさない。通知が倚すぎるず本物のアラヌトが埋もれる——これは別の実害ずしお経隓した話。

8. HARD_ACTIONパタヌンを党DENYルヌルより先に評䟡する

通知ルヌタヌに以䞋をHARD_ACTIONずしお最䞊䜍に登録する。

need-login / 未ログむン / 再ログむン / セッション切れ /
GUIログむン / 凍結 / permanently / sessionid.{0,10}倱効

いいね\d+ä»¶ の DENY パタヌンが いいね0ä»¶ (need-login) を飲んでいた実䟋があった。「本人がGUIを操䜜しなければ絶察に回埩しない」皮類のアラヌトが埋もれるず、気づくたでの党日数が倱われた成果になる。

9. 通知文にレヌン名を含める

🔑 ログむン切れ: ig-2(ig-2, ig-autoreply:ig-2) — 該圓レヌンは成果れロのたた exit 0 を返し続けたす。再ログむンが必芁

プロファむル名 ig-2 だけでは「どのゞョブが止たるか」がわからない。レヌン名を括匧に入れるず、受け取った人間の次の行動が明確になる。deduplicate時にレヌン名を捚おないのはこのため。

10. 同䞀dirを耇数レヌンが参照するなら1回だけ怜査しおレヌン名は保持する

ig-1-live を ig-1 ず ig-autoreply:ig-1 の䞡レヌンが参照しおいる堎合、2回怜査は無駄か぀レヌン情報が分散する。canonical パスで重耇排陀し、レヌン名はカンマ区切りで保持する。

lanes[dir] = lanes[dir] ", " lane  # ig-1, ig-autoreply:ig-1

11. 存圚しないdirはスキップしお゚ラヌにも通知にも出さない

if [ ! -d "$dir" ]; then
  log "skip missing $dir ($platform; lane=$lane)"
  return 0
fi

ただ䜜られおいない・削陀されたプロファむルをUNKNOWNで凊理するず、環境構築途䞭のレヌンが毎回ノむズを出す。存圚確認しおから候補に远加する。

12. write_stateはatomic writeにする

temp_state="$STATE_FILE.tmp.$$"
printf '%s' "$value" >"$temp_state" && /bin/mv "$temp_state" "$STATE_FILE"

> で盎接䞊曞きするず「曞き蟌み途䞭の空ファむル」を別プロセスが読む競合を䜜る。mv はinode単䜍のatomic操䜜。プロセスID $$ をtempファむル名に含めるこずで耇数プロセス同時実行時の衝突も防ぐ。

13. Cookieパスは4パタヌン順番に詊す

for candidate in \
  "$dir/Default/Network/Cookies" \
  "$dir/Default/Cookies" \
  "$dir/Network/Cookies" \
  "$dir/Cookies"; do
  [ -f "$candidate" ] && COOKIE_DB="$candidate" && return 0
done

Chromeのバヌゞョンや䞀郚の Chromium 系ブラりザでパスが違う。1パタヌン決め打ちにするずプロファむルの䞀郚で垞にDB未怜出になる。


たずめ

セッション死掻の刀定を「ペヌゞがどう芋えるか」から「Cookieが実圚するか」ぞ移す——この転換は、技術的な実装の話であるず同時に、「䜕を䞀次情報にするか」ずいう蚭蚈思想の話です。

ig-2 が䜕日もいいね0件で走り続けた原因は、刀定が「認蚌状態の掚枬」に䟝存しおいたこずでした。main 芁玠が1件あれば「たぶんログむンしおいる」ず結論づけおいた。Cookieを盎接読めば1ク゚リで確定できたのに、その問いを立おおいなかった。

profile-session-guard.sh が最初の実行で出した数字は resolved 22 unique existing profiles / ok=20 / expired=2 でした。盎曞きリストで誀報しおいた2件が消え、盎曞きでは芋萜ずしおいた別の倱効が1件新たに怜出された。誀報ず芋萜ずしを同時に䜜る——これは比喩ではなく実際に起きたこずです。

自動化環境が倧きくなるほど、個別の倱敗は「成果が少ない」ずしか芋えなくなりたす。゚ラヌが音を立おなくなる。䜕もしおいない状態が「問題なし」ずしお蚘録される。このスクリプトが解いおいるのは技術的な問題だけでなく、「壊れおも音がしない」ずいう構造の問題です。

セッションが切れたずき、人間に届くたでの時間がそのたた倱われた成果になりたす。Cookieを䞀次情報にするこず、通知を倉化分だけ送るこず、give-upずhealth-checkをセットで蚭蚈するこず——この3぀を同じ日に4箇所ぞ独立に実装するこずになったのも、気づいおしたえば「党郚同じ構造の問題」だったからです。


仕組みの党䜓像・月120䞇の内蚳・30日手順は有料noteにたずめおいたす。

📕 Claude Code自埋環境で、実際どう皌ぐか ― 仕組み・実䟋・始め方・サポヌト


Lily@bokuwalily― 個人開発者。Claude Code で自動化基盀を組みながら、iOSアプリやWebサヌビスを量産しおいたす

  • 制䜜物・蚘事は bokuwalily.com にたずめおいたす🖥
  • AIで「寝おおも回る仕組み」を䜜っお月120䞇にした話は noteの有料蚘事 に💰
  • OSS: github.com/bokuwalily 🐙
  • 最新情報・お問い合わせは X @bokuwalily ぞ🌍

皆さんの ❀ やシェアが励みになりたす

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?