rya-res status: обе машины одним экраном. Очереди те же — render_queue.py <кто> --idle-pass 240 -- …, модели — mlx_queue.py; они сами ждут сторожа и дают модели потолок кэша. Задача с явными входами и выходами — rya-res run … --where auto: занят макбук — уедет на Memex по кабелю. ⏸ в Telegram — сторож заморозил фоновую задачу, чтобы макбук не упал; продолжит её сам.Роман 11.10: «умная система распределения ресурсов на рендер и на всё остальное между макбуком и мемексом, чтобы у меня не выключился он (может быть замки делать), и при этом максимум ресурсов использовали». С 07.10 по 11.10 макбук перезагружался семь раз; корень почти всегда один — память. Слой scripts/18_compute/, команда rya-res.
ae.rya.res-guard, раз в 5 с: рост свопа (сам своп липкий), свободная память, давление, место на внутреннем диске (там своп), нагрев, батареяytai_mlx_cap.pth во всех ~/YTAI/environment/.venv_* на обеих машинах: потолок у любой модели, даже мимо очередейYTAI_MLX_CACHE_GB, без — YTAI_MLX_CAP=0render.lock); vt — VideoToolbox (M3 Max — два медиадвижка, M4 — один); mlx — одна модель (тот же mlx.lock)rya-res run <кто> --kind cpu|vt|mlx --est-min M --in ВХОД --out ВЫХОД -- команда {in} {out}ssh memex-tb (169.254.77.1): шифр aes128-gcm 279 МБ/с, по умолчанию на загруженном маке 68Замок в коде — ~/.cache/ytai/render.lock; на диске виден как RENDER.lock (первым его создал render_gate.py, файловая система регистр не различает) — файл один, обёртки две. Дорожка Memex — целевой протокол, надо построить: сегодня таймаут = код 75 и провал, на Memex уходят руками по правилу «мак забит», рендер HyperFrames идёт туннелем, кеш там никто не чистит.
Дорожка «Рендер» из схемы крупно — в том порядке, в каком её проходит render_queue.py.
render_queue.py <кто> -- команда⇒ опрос раз в 10 с (RENDERQ_POLL)Порядок — как в коде render_queue.py: замок берётся первым и отпускается, если мешает чужой рендер или память. Пороги остальных процессов — в таблице «Что считается занятостью» ниже; 03.10 новичок так обогнал ждущего 57 мин — «Честная очередь» в разделе «Надо построить».
<кто> [--max-wait SEC] [--idle-pass SEC] -- команда; замок ~/.cache/ytai/render.lock на одну команду, внутри «кто pid время»RENDERQ_MAX_SWAP_GB и RENDERQ_MAX_PRESSURE (1 норма · 2 · 4); опрос раз в RENDERQ_POLL (10 с); потолок 6 ч → код 75--idle-pass 240: замок занят, но тяжёлого рендера нет 240 с → идёт без замка; держатель, уже признанный лёгким, пропускается сразуRENDERQ_BLOCK=1 — ждать сам замок, только коротким; журнал — stdout вызывающего--label ИМЯ --max-wait 30 --log ФАЙЛ -- команда; --status печатает чужие рендеры; зовут autocut.py, audio_io.py, screens_hf.pynice -n 5; память не смотрит<кто> -- команда; замок ~/.cache/ytai/mlx.lock; чужой = python с mlx_*, venv_*, wordrole_transcribe, стадиями ревью; памяти ≥ 30 %; потолок 3 ч → код 75venv_transcribe ловит не-модели: рендер звать системным python3_Proxy/, proxy.py) SIGSTOP и отпускает SIGCONT; опрос 5 с; --thaw чинит падение~/.cache/ytai/LOAD.json {job, code, stage, started, expected_min, host}; пишут review.py и ~/bin/ytai_load start; wait_load ждёт чужой флаг, сон 60 с, потолок 480 мин → код 5--idle-pass 240, своп 12, давление 1; cut.py — --par 1; 0512_reversion — пачкой под одним замком, своп 16--par 2 — против правила «по одной части»; у autocut порогов свопа нет| Процесс | render_queue.py | render_gate.py | busy_gate · pause_guard |
|---|---|---|---|
| ffmpeg | ≥ 150 % CPU | ≥ 150 % и старше 25 с | любой чужой; ffprobe не считается |
| x264 · x265 · HandBrakeCLI | ≥ 100 % | ≥ 150 % | HandBrakeCLI — любой чужой |
| Adobe Media Encoder | ≥ 150 % | ≥ 150 % | Adobe ≥ 0,4 машины — стоп |
| Adobe Premiere Pro | ≥ 300 % | не смотрит | в доле Adobe; открытый без дела не держит |
| chrome-headless-shell · hyperframes | ≥ 100 % | chrome ≥ 150 % | не смотрит |
| After Effects · aerender | ≥ 200 % | не смотрит | AfterFX — в доле Adobe |
| Память | свободно ≥ 30 %; своп, давление по RENDERQ_* | не смотрит | load ≤ ядра × 1,5 до старта |
| «Свой» процесс | этот процесс и потомки | общий предок | метки в командной строке |
rclone держит только прокси с заливкой; Compressor — gate и прокси. Чего нет (надо построить): бюджета ядер и памяти — всё держится на «одном тяжёлом»; аппаратный кодек не отличается от x264; шаги вне обёртки (qc.py на 497 %, пробы, приёмка) замок не берут, а для чужих очередей выглядят чужим рендером.
| Когда | Что случилось | Что сделали | Состояние |
|---|---|---|---|
| 28→29.09 | мак упал, своп 34 ГБ: два Qwen2.5-VL + whisper + OCR разом | mlx_queue.py: модели по одной | есть сегодня |
| 02.10 14:26 | паника ядра, своп 38 ГБ при 36 ГБ памяти: чужой python 20–25 ГБ + два x264 4K; memory_pressure показывал 36 % свободно | пороги свопа и давления; одна часть за раз (19 к/с одной, 21 двумя); запуск из снимка кода; YTLAB01 дорендерен по одной части | есть; пороги ставит каждый вызывающий сам |
| 02.10 | приёмка файла YTEVO02 в один поток держала замок 2 ч, три очереди стояли | --idle-pass 240 | есть; шапка кода говорит «полчаса», память — «2 часа» |
| 24.09 | Premiere на 98,7 % CPU — одно ядро из 14 — заморозил прокси на 30 мин | порог Adobe ≥ 0,4 машины | есть сегодня |
| 03.10 ночь | короткая задача (10 мин работы) час стояла за пятью длинными; в 00:50 нагрузка 52 при 14 ядрах, своп 7,9 → 9,2 ГБ, замок ушёл самому новому из пяти ждущих, qc.py вне очереди на 497 % | RENDERQ_POLL, RENDERQ_BLOCK=1 коротким | есть; порядок, бюджет, панель — открыто |
| 07.10 | whisper YTTRBM02 (61 мин) дорос до 27 ГБ, своп 23 ГБ — на внутреннем диске осталось 128 МБ | chunk_whisper.py: куски по 10 мин, кэш MLX чистится после каждого | есть; с 12.10 — потолок MLX у всех |
| 07–11.10 | макбук перезагружался 7 раз: зависания при выключении, jetsam | диспетчер rya-res, сторож на обеих машинах | есть с 12.10 |
| 11.10 23:41 | своп 16,5 → 19 ГБ за 20 с: whisper YTCH10 (38 мин) держал 29 ГБ кэша MLX; Memex — 4 из 10 ядер, 72 % памяти свободно | процесс заморожен; перезапуск с готового whisper (диаризация 2 мин); потолок MLX 2 ГБ во все окружения; сторож | есть с 12.10 |
| 12.10 | очередь моделей ждала свою же проверку lsof 16–40 с на каждом заходе | lsof -n -P → 0,1 с | есть с 12.10 |
Рендер на железе — узкое горлышко. Считаем время до результата по обоим путям и берём меньшее; оценку пишем в статус. Если Memex — только через Google Drive, с проверкой «всё передали» и очисткой кеша там.
ssh memex через Tailscale; диск 460 ГБ, 03.10 свободно 177; часы на час вперёдexport PATH=/opt/homebrew/bin:$PATHRENDERQ_BLOCK=1 RENDERQ_POLL=2, отдельные кадры — мимо очереди; на Memex — только когда оценка меньше с запасом (порог — решает Роман)memex_space_guard.shmemex/push.sh), запуск nohup caffeinate -dims + watchdog.sh, кат серверной копией в 03_Exports, назад pull.sh --no-framesmemex_render.sh (rsync → nohup → файл с кодом → scp), без Drive и без очистки; там hyperframes 0.8.103, у фильмов 0.8.106Роман, 03.10.2026: «ещё один из процессов — узкое горлышко рендер на железе, надо делать умно распределение между макбуком и мемексом. Выбирать наиболее быстрый способ и правильно делать. Если на мемекс — то через гугл диск, следим, что мы всё передали, что мемекс всё загрузил на гугл потом и очистил весь кеш (место там важно). Чтобы не было так, что на макбуке очередь, а на мемексе пусто. И при этом не было так, что если это быстро можно сделать на макбуке, а мы грузим долго и сложно на мемекс».
Полосы — в МБ/с (МиБ × 1,05). Туннель для больших файлов не использовать. Модели на Memex в 2,6 раза медленнее мака; рендер x264 и HyperFrames там не замерен.
Лизы, журнал дозаписью, подтверждение размером с Drive, STOP и PAUSE, сторож — уже есть у фермы прокси (чипы ниже), брать оттуда. Чего нет нигде: захвата, который видят обе машины, и очистки с подтверждением.
| Слагаемое | Скорость | Откуда | Состояние |
|---|---|---|---|
| Ожидание в очереди мака | по журналу ожиданий | журнала нет | надо построить |
| Заливка с мака на Drive | ≈ 9 МиБ/с (15.09) | память reference_memex_mlx_stack | есть; в обход VPN — замерить |
| Скачивание на Memex с Drive | 36 МБ/с (20–41) | отчёт 10, замер 15.09 | есть |
| Модели на Memex | в 2,6 раза медленнее мака | VLM 15,1 → 40 с на экран | есть |
| Рендер x264 и HyperFrames на Memex | не замерен | — | замерить — надо построить |
| Выгрузка результата Memex → Drive | не замерена | — | замерить — надо построить |
| Скачивание на мак с Drive | 35 МиБ/с в обход VPN, 9,5 через VPN | замер 28.09 | есть |
| Туннель мак → Memex | ≤ 1,3 МБ/с, бывало 11 КБ/с | 15.09, 30.09 | для больших файлов не использовать |
Ферма не распределённая: на каждой машине один процесс со своей очередью, писатель журнала один, Drive — истина о сделанном. Для рендера через Drive не хватает захвата, который видят обе машины.
tg_status.py --job J [--every 300] (headless): одно сообщение, правится editMessageText; строки Этап / Идёт / Готово / Скачивание / Части / До конца / Дальше / Жду; выход по finished, STOP_STATUS или через 24 чsc_status.py <проект> [--every 300] (story_cut): части X из Y с минутами, графика X из Y, «Очередь рендера: мы / кто»; вехи и сбои — Job.tg отдельно, файлы — Job.tg_file до 50 МБytuvi_progress.py: HTML-панель с полосками, история progress_history.jsonl → скорость и ETA по окну 45 мин; сообщение раз в 10 мин простым текстом--parse html|md2|none), rich, poll, react, photo, video, raw; правка — raw editMessageText; документ — tg.call(…, 'sendDocument', files=)date; своп растёт — чей процессОчередь рендера · мак · 00:55 Идёт: ytevo02-v7-deliver · с 00:30 · ffmpeg 860 % · готово 31 из 50 частей Ждут 5: ytlab01-v4-check 50 мин · ещё трое 36 · 33 · 20 мин · новый 35 с Мак: нагрузка 52 на 14 ядер · своп 7,9 → 9,2 ГБ за 8 мин · давление 1 Вне очереди: qc.py 497 % — тяжёлый без замка Memex: свободен · второй ждущий (36 мин) уедет туда через Drive: замок держит чужой рендер Дальше на маке: ytlab01-v4-check — первый по приходу
Нагрузка, своп, держатель и ждущие — из замера 03.10 00:50; «готово 31 из 50» — для примера. Жирным — только первая строка. Одно сообщение правится раз в 5 мин; картинка с полосками (как у ytuvi_progress) — отдельным photo. Сегодня такого статуса нет: у каждого конвейера своё сообщение без свопа и «почему Memex».
rya-res gate; RENDERQ_MAX_SWAP_GB у вызывающих больше не нужен~/.cache/ytai/res/state.json каждые 5 с, events.jsonl — паузы, разморозки, уровни; сколько ждали в очереди — ещё нетrya-res run --where auto — для задач с явными входами и выходами; через Drive и для этапов целиком — ещё нет (Memex не видит SSD макбука)stage_snapshots/<прогон>/ одной командой с git sha; 999_extra и 17_audio копией, не ссылкой| Проверка | Когда | Норма | Откуда взялась |
|---|---|---|---|
| Чужой рендер | перед запуском и пока ждём | нет процессов тяжелее порогов; render_gate.py --status | Роман 02.10: «когда не занят другим рендером» |
| Свободная память | перед запуском | ≥ 30 % по memory_pressure -Q | 28→29.09, своп 34 ГБ |
| Своп и давление | перед запуском и в каждом статусе | своп ≤ 12–16 ГБ, давление ≤ 1–2; sysctl vm.swapusage | паника ядра при «36 % свободно» |
| Кто держит замок | перед своим рендером, глазами | cat ~/.cache/ytai/render.lock + ps; имя может быть старым | 02.10: «главное, смотри, что мак свободен» |
| Одна часть за раз | длинный фильм | --par 1; готовые части сверить по числу кадров | 19 к/с одной, 21 двумя |
| Мак освободился? | перед каждым рендером на Memex | вернуться на мак; в статусе — «почему Memex» | Роман 02.10 |
| Путь выбран по оценке | перед каждым тяжёлым шагом | T мак vs T Memex, оценка в статусе — открыто | Роман 03.10: «выбирать наиболее быстрый способ» |
| Всё передано | перед стартом на Memex | размер и md5 на Drive = на маке — открыто | Роман 03.10: «следим, что мы всё передали» |
| Результат выгружен и сверен | после работы Memex | размер и md5 на Drive = на Memex; мак скачал и сверил — открыто | Роман 03.10 |
| Кеш Memex очищен | после сверки результата, до закрытия задания | входы, кеш и результат на Memex стёрты — открыто | Роман 03.10: «место там важно» |
02.10 мак ушёл в панику при «36 % свободно»: одного процента мало — поэтому ещё своп и давление.
Порог ставит каждый вызывающий сам: sc_run.py 12, 0512_reversion 16, у autocut — нет.
kern.memorystatus_vm_pressure_level; норма проверок — ≤ 1–2.
Числа — из таблицы проверок и случаев выше; переменные и порядок — render_queue.py.
| Файл | Что хранит | Кто пишет | Состояние |
|---|---|---|---|
| ~/.cache/ytai/render.lock · mlx.lock | кто, pid, время держателя | обёртки при взятии; не стирается | есть; имя устаревает |
| ~/.cache/ytai/render_idle_pass.txt | держатель, признанный лёгким | render_queue.py --idle-pass | есть |
| ~/.cache/ytai/LOAD.json (Memex) | job, code, stage, started, expected_min, host | review.py, ytai_load | есть, рекомендательно |
| 00_Setup/08_Cut/status.json · tg_status_msg.json | этап, строка, готово, eta; id живого сообщения | Job.status; tg_status.py, sc_status.py | есть |
| 00_Setup/logs/storycut_<tag>.log · autocut_gate.log | строки ожидания [renderq], [gate:…] | обёртки через stdout вызывающего | есть, разрозненно |
| ~/.cache/ytai/stage_snapshots/<прогон>/ | снимок кода этапа для длинного прогона | сессия руками | есть; инструмента нет |
| queue.jsonl — журнал очереди | приход, ожидание, к/с, своп | обёртка | надо построить |
Случаи с датами — в таблице выше; здесь то, что ловится только кодом или глазами.
rya-res status # обе машины: уровень, память, нагрев, замки, пауза, очередь, тяжёлые rya-res gate --kind mlx # можно ли начинать тяжёлое: rc 0 — да, rc 1 — нет и почему rya-res run <кто> --kind mlx --where auto --est-min 6 --in ВХОД --out ВЫХОД -- <команда {in} {out}> # сама выберет машину; на Memex — по кабелю rya-res thaw # разморозить всё, что заморозил сторож rya-res install && rya-res install --memex # поставить или обновить; сторож меняет код без разморозки
Старые вызовы очередей работают как были — диспетчер подключён внутри render_queue.py и mlx_queue.py.
X=~/YTAI/scripts/999_extra; SC=~/YTAI/scripts/05_editing/0511_story_cut python3 $X/render_queue.py <кто> --idle-pass 240 -- <команда …> # общий замок, чужой рендер, память ≥ 30 % RENDERQ_MAX_SWAP_GB=12 RENDERQ_MAX_PRESSURE=1 python3 $X/render_queue.py <кто> --idle-pass 240 -- <команда …> # ещё своп и давление RENDERQ_BLOCK=1 RENDERQ_POLL=2 python3 $X/render_queue.py <кто> -- <короткая команда> # короткая задача ждёт сам замок nohup caffeinate -ims python3 $SC/sc_run.py film $P & # фильм story_cut: графика части → часть, порции через очередь, системным python3 python3 $X/mlx_queue.py <кто> -- <команда с моделью> # модели по одной
Шаг этапа Cut: python3 $X/render_queue.py … · caffeinate -ims python3 $SC/sc_run.py film → sc_conform. Длинный прогон — из снимка кода, не из живого этапа.
cat ~/.cache/ytai/render.lock # кто pid время — имя может быть старым, замок при этом свободен python3 ~/YTAI/scripts/05_editing/0510_autocut/render_gate.py --status # чужие тяжёлые рендеры по правилам gate ps -Ao pid,pcpu,etime,command | grep -E 'ffmpeg|chrome-headless|hyperframes|x264' | grep -v grep # что реально ест процессор memory_pressure -Q; sysctl vm.swapusage; sysctl -n kern.memorystatus_vm_pressure_level; uptime # память, своп, давление (1 норма · 2 · 4), нагрузка ssh memex 'export PATH=/opt/homebrew/bin:$PATH; uptime; df -h ~ | tail -1; cat ~/.cache/ytai/LOAD.json' # занят ли Memex, сколько места
python3 $R/review.py memex push · start · status · pull --no-frames # ревью на Memex: код rsync, кат с Drive, результат назад python3 ~/YTAI/scripts/16_proxy/pause_guard.py --thaw # разморозить свои ffmpeg после падения сторожа
python3 ~/YTAI/scripts/05_editing/0511_story_cut/sc_status.py $P --every 300 # живое сообщение story_cut; headless — tg_status.py --job $J python3 ~/bin/tg.py text rya $CHAT "<b>Очередь</b> …" --parse html --no-preview # веха; есть теги — только html; картинка — tg.py photo