# Handoff: Fission poolmgr reuse still broken after partial fix ## Goal Нужно разобраться, почему в live Fission при последовательных invoke одной и той же function с executor `poolmgr` executor каждый раз снова делает `choosePod + specializePod`, вместо reuse уже существующего specialized pod/function service. Ключевой симптом: - после завершения invoke resources не reuse-ятся для следующего вызова; - executor продолжает создавать новый specialized pod почти на каждый invoke; - для тяжелых функций это приводит к росту pod count и затем к timeout/504. ## Environment - Local workspace: `/home/naeel/remote_dev/fission` - Remote console repo: `/home/naeel/terra/fission` - Remote Fission runtime repo: `/home/naeel/terra/fission-src` - Live cluster access only via SSH: ```bash ssh -i ~/.ssh/naeel_vm_id_ed25519 -o StrictHostKeyChecking=no -o ConnectTimeout=10 naeel@5.172.178.213 '...' ``` - Fission namespace: `fission` - Live user namespace under test: `fission-ffd1f598c169b0ae` ## Functions under test Namespace: `fission-ffd1f598c169b0ae` - `phppp` - env: `console-php-env` - executor: `poolmgr` - route: `/f598c169b0ae/phppp` - `88` - env: `console-python-env` - executor: `poolmgr` - route: `/f598c169b0ae/88` HTTP invoke path used for live validation: ```bash https://fission.kube5s.ru/fn/f598c169b0ae/phppp https://fission.kube5s.ru/fn/f598c169b0ae/88 ``` Valid user token used for direct invoke is in: - `/home/naeel/remote_dev/terraform/TEST_STAND/POSTGRES/terraform.tfvars` - remote mirror: `/home/naeel/terra/terraform/TEST_STAND/POSTGRES/terraform.tfvars` ## What was already found earlier Изначально казалось, что проблема только в namespace quota saturation, потому что при многократных invoke возникали `504`, а quota по CPU/memory/pods реально упирались в потолок. Но затем был найден реальный runtime bug: - reuse key в executor uses `UID + ResourceVersion + Generation` - `CacheKeyURGFromMeta(...)` in `pkg/crd/key.go` - router/executor client path previously sent `FnMetadata` in `TapService`/`UnTapService` without `Generation` - из-за этого `UnTapService -> MarkAvailable` не попадал в тот же cache key - `activeRequests` не уменьшался у правильного cached function service - следующий invoke видел cache miss и создавал новый specialized pod ### Previous fix already made File changed in runtime repo: - `pkg/executor/client/client.go` Change: - added `Generation: fnMeta.Generation` in `TapService(...)` - added `Generation: fnMeta.Generation` in `UnTapService(...)` Remote commit already made: - `775845b executor: preserve generation in untap metadata` ## Important: this fix is already rolled out to live New bundle image built and deployed: - image: `naeel/fission-bundle:v1.22.0-multi-ns-9` - digest: `sha256:5348bca2eacb78a030e639d7f4f7ac392369b6f702677ac47a69ea9f61f50a12` Live deployment state after rollout: - `router` image = `naeel/fission-bundle:v1.22.0-multi-ns-9` - `executor` image = `naeel/fission-bundle:v1.22.0-multi-ns-9` So: the `Generation` fix is **already in live**, but reuse is **still broken**. ## Current live reproduction ### `phppp` Command pattern: ```bash USER_TOKEN=$(grep -m1 '^api_token' /home/naeel/terra/terraform/TEST_STAND/POSTGRES/terraform.tfvars | sed -E 's/^api_token = "(.*)"$/\1/') curl -sk -o /tmp/phppp.out -w '%{http_code}' --max-time 40 \ "https://fission.kube5s.ru/fn/f598c169b0ae/phppp" \ -H "Authorization: Bearer $USER_TOKEN" ``` Observed result: - 10 of 10 invokes returned `200` - BUT php specialized pod count grew from `1` to `11` Exact observed summary: - `PHP_PODS_BEFORE=1` - invokes `1..10`: all `HTTP=200` - `PHP_PODS_AFTER=11` This proves: - invoke itself works - auth token is valid - runtime is still specializing a new pod on each invoke instead of reusing ### `88` Command pattern: ```bash USER_TOKEN=$(grep -m1 '^api_token' /home/naeel/terra/terraform/TEST_STAND/POSTGRES/terraform.tfvars | sed -E 's/^api_token = "(.*)"$/\1/') curl -sk -o /tmp/88.out -w '%{http_code}' --max-time 40 \ "https://fission.kube5s.ru/fn/f598c169b0ae/88" \ -H "Authorization: Bearer $USER_TOKEN" ``` Observed result: - first 3 invokes returned `200` - then invokes 4..10 returned `000` / timeout-like failure from curl - python pod count grew from `1` to `4` Exact observed summary: - `PY_PODS_BEFORE=1` - tries 1..3: `HTTP=200` - tries 4..10: `HTTP=000` - `PY_PODS_AFTER=4` This suggests: - same reuse bug path still exists for python too - when function is heavier, pod growth quickly returns the original operational problem ## Most important executor logs After rollout, executor logs still show for `phppp` on nearly every invoke: - `choosing pod from pool` - `relabel pod` - `specializing pod` - `added function service` Example pattern repeated for each invoke: ```text choosing pod from pool relabel pod chose pod ... poolmgr-console-php-env-...-5dcc862z4hm calling fetcher to copy function specializing pod specialized pod ... podIP=172.16.1.80 added function service ... serviceHost=172.16.1.80:8888 choosing pod from pool relabel pod chose pod ... poolmgr-console-php-env-...-5dcc86k2zlk calling fetcher to copy function specializing pod specialized pod ... podIP=172.16.3.209 added function service ... serviceHost=172.16.3.209:8888 choosing pod from pool relabel pod chose pod ... poolmgr-console-php-env-...-5dcc86ftzfp calling fetcher to copy function specializing pod specialized pod ... podIP=172.16.3.52 added function service ... serviceHost=172.16.3.52:8888 ``` That is, executor behavior in live clearly remains: - no effective reuse of existing function service - no steady-state one-pod serving repeated invokes Also later there is only idle cleanup like: ```text release idle function resources function=phppp address=172.16.2.155:8888 ``` That confirms pods are being reaped later, but not reused immediately for next request. ## What is already ruled out ### Not an auth issue - token from `terraform.tfvars` is valid - direct `/fn/...` invoke works with bearer token ### Not just quota - quota pressure was real earlier - but now we have a cleaner reproduction where repeated invoke still creates new specialized pod even before total failure - for `phppp`, 10 requests succeed but pod count still grows `1 -> 11` ### Not only missing `Generation` anymore - `Generation` was indeed missing before - that fix is already committed, built, deployed - live logs prove reuse is still broken after that fix ## Highest-value question now Where else in the path does executor fail to map the completion of request back to the existing cached function service? In other words: why does `UnTapService -> MarkAvailable` still not make the current function service reusable for the next invoke? ## Narrow code path to inspect Please focus on the smallest path controlling release/reuse: - `pkg/router/functionHandler.go` - request lifecycle - `getServiceEntry` - `unTapService` - what metadata and service URL/address are sent back after request completes - `pkg/executor/client/client.go` - `TapService(...)` - `UnTapService(...)` - `pkg/executor/api.go` - `/v2/getServiceForFunction` - `/v2/unTapService` - `/v2/tapServices` - `pkg/executor/fscache/functionServiceCache.go` - `GetFuncSvc` - `AddFunc` - `MarkAvailable` - `TouchByAddress` - `pkg/executor/fscache/poolcache.go` - activeRequests accounting - `markAvailable` - `pkg/executor/executortype/poolmgr/gp.go` - `getFuncSvc` - `choosePod` - `specializePod` - `pkg/executor/executortype/poolmgr/gpm.go` - `TapService` - `UnTapService` - idle reaper logic - `pkg/crd/key.go` - `CacheKeyURGFromMeta` ## Strong suspicion There is still a mismatch in at least one of these dimensions: 1. metadata key used by cache lookup / mark available 2. service address format used for matching existing function service 3. path by which router reports completion back to executor 4. activeRequests decrement path in pool cache 5. tap/untap batching behavior versus per-request lifecycle ### Concrete symptoms that support this - every next invoke still enters `choosePod` - `added function service` repeats with new pod IP every time - there is no visible log evidence that the just-used address became available in time for the next invoke ## Helpful concrete questions for investigation 1. Does router send the same logical function identity on `getServiceForFunction` and `unTapService` after the `Generation` fix, or is there still some field mismatch? 2. Is `serviceURL`/address normalized differently between tap and untap, so the address cannot match the cached function service? 3. Does `MarkAvailable` expect `serviceHost` without scheme while router sends full URL or vice versa? 4. Is `activeRequests` decremented on the same object/key that `GetFuncSvc` checks on the next invoke? 5. Could `TouchByAddress` / `MarkAvailable` be operating on a stale or different cache entry than `AddFunc` created? 6. Is the router definitely calling untap on successful invoke for these direct `/fn/...` requests? 7. Is there any race where the next invoke starts before previous untap is processed, making this appear as no reuse even for sequential calls with ~4-5s spacing? 8. For `phppp`, since calls are sequential and each lasts ~4s, why is a new pod still chosen 5 seconds later if previous invoke already completed? ## Useful live commands already used Check live deployment images: ```bash ssh -i ~/.ssh/naeel_vm_id_ed25519 -o StrictHostKeyChecking=no -o ConnectTimeout=10 naeel@5.172.178.213 \ 'kubectl describe deploy router -n fission | sed -n "/Containers:/,/Conditions:/p"' ssh -i ~/.ssh/naeel_vm_id_ed25519 -o StrictHostKeyChecking=no -o ConnectTimeout=10 naeel@5.172.178.213 \ 'kubectl describe deploy executor -n fission | sed -n "/Containers:/,/Conditions:/p"' ``` Check function and trigger: ```bash ssh -i ~/.ssh/naeel_vm_id_ed25519 -o StrictHostKeyChecking=no -o ConnectTimeout=10 naeel@5.172.178.213 \ 'kubectl get function phppp -n fission-ffd1f598c169b0ae -o yaml | sed -n "1,220p"' ssh -i ~/.ssh/naeel_vm_id_ed25519 -o StrictHostKeyChecking=no -o ConnectTimeout=10 naeel@5.172.178.213 \ 'kubectl get httptrigger phppp-route -n fission-ffd1f598c169b0ae -o yaml | sed -n "1,220p"' ``` Live smoke used to prove bug remains: ```bash ssh -i ~/.ssh/naeel_vm_id_ed25519 -o StrictHostKeyChecking=no -o ConnectTimeout=10 naeel@5.172.178.213 <<'SSH' set -e USER_TOKEN=$(grep -m1 '^api_token' /home/naeel/terra/terraform/TEST_STAND/POSTGRES/terraform.tfvars | sed -E 's/^api_token = "(.*)"$/\1/') NS=fission-ffd1f598c169b0ae BEFORE=$(kubectl get pods -n "$NS" --no-headers | grep 'poolmgr-console-php-env' | wc -l) echo "PHP_PODS_BEFORE=$BEFORE" for i in 1 2 3 4 5 6 7 8 9 10; do code=$(curl -sk -o /tmp/phppp.out -w '%{http_code}' --max-time 40 "https://fission.kube5s.ru/fn/f598c169b0ae/phppp" -H "Authorization: Bearer $USER_TOKEN" || true) body=$(tr '\n' ' ' /dev/null | head -c 200 || true) echo "TRY=$i HTTP=$code BODY=$body" done AFTER=$(kubectl get pods -n "$NS" --no-headers | grep 'poolmgr-console-php-env' | wc -l) echo "PHP_PODS_AFTER=$AFTER" SSH ``` Executor logs: ```bash ssh -i ~/.ssh/naeel_vm_id_ed25519 -o StrictHostKeyChecking=no -o ConnectTimeout=10 naeel@5.172.178.213 \ 'kubectl logs -n fission deploy/executor --since=15m | egrep "phppp| 88 |functionName=88|choosing pod from pool|specializing pod|added function service|marking function service|MarkAvailable|tapService|unTapService" | tail -n 240' ``` ## What is wanted from Sonnet Не просто общая гипотеза, а конкретно: 1. pinpoint the next exact root cause in code 2. explain why the already-deployed `Generation` fix was necessary but insufficient 3. propose the smallest correct patch 4. say exactly how to validate that patch in live Best outcome: - a minimal patch in one or a few files - explanation of the failing cache/release path - exact reason repeated invokes still go through `choosePod` after success of prior invoke