Staff PC Deployment · Operations
I ship KakaoTalk and Instagram work to 11 staff PCs with a one-line install and run it there (as registered on 2026-09-16)
KakaoTalk and Instagram have no official API a server can call. So the work had to run on staff Macs and Windows PCs. Install is a one-line command, auth is a per-device key, and updates run on an automatic schedule per tool. I also run the servers myself. On 2026-08-20 a cloud DB quota stopped every work-tool API; I stood up the same API on a VM and restored service that day.
- An install token is consumed in a single UPDATE. If lookup and mark-as-used are separate, two PCs can register at once with one token. Registration passes only when an UPDATE conditioned on used_at IS NULL and expiry returns a row. Failure reasons are split into sentences staff can read. If one device is compromised, only its row is revoked.
- zip hashes instead of version numbers. The sha256 of the published zip is the version. There is no separate version ledger, so the ledger and the file cannot drift apart. Workers swap only between jobs and simply exit. Restarting is the job of launchd and Task Scheduler. If a worker relaunched itself and two came up, the Instagram profile would break.
- Update times differ per PC. If every device updates in the same minute, there is no window to pull a bad release. Mac real-time sync picks only a random minute within 14:00, and keeps that minute across reinstalls. The Windows CS tool downloads at a random time between 09:00 and 18:59, and tries once more 2 minutes after logon.
- On Windows, KakaoTalk uses a read-only collector. The collector opens read access only and never writes.
- Send success is checked in the DB, not by exit code. On 2026-09-07 only the photo went out, the text was missing, and the job was still marked sent. Now it reads the local KakaoTalk DB right after sending and fills in only the missing part, once, on the spot. If the photo does not show up, it waits longer in case the upload is slow. Two copies of a photo in a 70-person room is worse than a lost message.
- Device assignment and conditional claims are layered. On 2026-07-29 a dev Mac picked up the queue of a Mac reserved for remote work. Successes and failures alternated, and finding the cause took a day. Now a worker exits immediately if it is not the assigned host. A claim is a conditional UPDATE on status='pending', and the open-chat queue has UNIQUE(send_date, room_name) as a second guard.
- Device blocks reach workers immediately via push. The push hub listens on Postgres LISTEN/NOTIFY and wakes workers over SSE. When device_keys changes, it re-authenticates before waking them. A blocked device gets revoked and its connection is closed. On the server side, filling the single revoked_at field is enough.
- deploy.sh re-runs itself from the version in the commit being deployed. The 2026-09-28 deploy failure happened because the running script differed from the script in the commit. The image tag is set once as sha-<commit>, and if the pull fails it stops instead of falling back to :latest. compose is rendered before the build, so missing variables are caught before a 40-minute build.
- 11 staff PCs