fix(acp_server_opencode): service PATH + bin var + surface adapter crash in validate (#21)
ACP readiness probe returned 000 for the full retry window on
xworkmate-bridge-ubuntu-26 (nothing listening = adapter crash-loop), but the
play aborted at the probe so the real cause never reached the CI log.
- systemd unit: add Environment=PATH ({{ acp_opencode_path }}, parity with the
launchd plist) so the lazily-spawned opencode/node CLI resolves; replace the
hardcoded --opencode-bin /usr/bin/opencode with {{ acp_opencode_binary_path }}
({{ npm_global_bin }}/opencode), matching the gemini/codex roles and macOS.
- validate.yml: wrap the readiness probe in block/rescue that dumps systemctl
status + journalctl on failure, so the adapter crash reason is visible.
- fix latent undefined var in the summary (acp_opencode_adapter_http ->
acp_opencode_adapter_probe), which would have errored once the endpoint came up.
Co-authored-by: Haitao Pan <manbuzhe2009@qq.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
e953d87f07
commit
4364786465
@ -11,6 +11,10 @@ acp_opencode_workdir: "{{ ansible_env.HOME | default('/home/' + acp_opencode_ser
|
||||
# user-level npm global bin lives under ~/.local/bin; include Homebrew + system.
|
||||
acp_opencode_npm_global_bin: "{{ acp_opencode_home + '/.local/bin' if ansible_os_family == 'Darwin' else '/usr/bin' }}"
|
||||
acp_opencode_path: "{{ acp_opencode_npm_global_bin }}:/opt/homebrew/bin:/opt/homebrew/sbin:/usr/local/bin:/usr/local/sbin:/usr/bin:/bin"
|
||||
# OpenCode CLI binary the adapter spawns lazily (mirrors gemini/codex which use
|
||||
# {{ acp_X_npm_global_bin }}/<cli>). Was hardcoded to /usr/bin/opencode in the
|
||||
# unit template; use the resolved npm global bin so macOS (~/.local/bin) works too.
|
||||
acp_opencode_binary_path: "{{ acp_opencode_npm_global_bin }}/opencode"
|
||||
acp_opencode_listen_host: 127.0.0.1
|
||||
acp_opencode_listen_port: 38992
|
||||
acp_opencode_packages: []
|
||||
|
||||
@ -20,33 +20,68 @@
|
||||
# 用 curl 重试循环替代 uri:服务刚 (重)启时 adapter 会先 accept TCP 但短时间内不
|
||||
# 应答(读挂起),而 uri 默认 30s 超时 + retries/until 在连接超时上不可靠循环(实测
|
||||
# 仅试一次即失败)。每次 5s 上限、真重试,给冷启动足够时间(adapter 就绪后 ~4ms 回 200)。
|
||||
- name: Validate OpenCode local ACP endpoint (readiness retry)
|
||||
ansible.builtin.shell: |
|
||||
set -eu
|
||||
url="http://{{ acp_opencode_listen_host }}:{{ acp_opencode_listen_port }}/acp/rpc"
|
||||
body='{"jsonrpc":"2.0","id":1,"method":"acp.capabilities","params":{}}'
|
||||
code=""
|
||||
for i in $(seq 1 30); do
|
||||
code="$(curl -s -m 5 -o /dev/null -w '%{http_code}' -X POST "$url" \
|
||||
-H 'Content-Type: application/json' -d "$body" 2>/dev/null || true)"
|
||||
if [ "$code" = "200" ]; then
|
||||
echo "OpenCode ACP endpoint ready after ${i} attempt(s)"
|
||||
exit 0
|
||||
fi
|
||||
sleep 2
|
||||
done
|
||||
echo "OpenCode ACP endpoint ${url} not ready after retries (last code: ${code:-none})" >&2
|
||||
exit 1
|
||||
args:
|
||||
executable: /bin/bash
|
||||
changed_when: false
|
||||
register: acp_opencode_adapter_probe
|
||||
# 包在 block/rescue:探针失败时把 systemctl status + journalctl 打到 CI 日志,
|
||||
# 否则 play 在此中止,看不到 adapter 进程真正的崩溃原因(如 last code 000)。
|
||||
- name: Validate OpenCode local ACP endpoint
|
||||
block:
|
||||
- name: Validate OpenCode local ACP endpoint (readiness retry)
|
||||
ansible.builtin.shell: |
|
||||
set -eu
|
||||
url="http://{{ acp_opencode_listen_host }}:{{ acp_opencode_listen_port }}/acp/rpc"
|
||||
body='{"jsonrpc":"2.0","id":1,"method":"acp.capabilities","params":{}}'
|
||||
code=""
|
||||
for i in $(seq 1 30); do
|
||||
code="$(curl -s -m 5 -o /dev/null -w '%{http_code}' -X POST "$url" \
|
||||
-H 'Content-Type: application/json' -d "$body" 2>/dev/null || true)"
|
||||
if [ "$code" = "200" ]; then
|
||||
echo "OpenCode ACP endpoint ready after ${i} attempt(s)"
|
||||
exit 0
|
||||
fi
|
||||
sleep 2
|
||||
done
|
||||
echo "OpenCode ACP endpoint ${url} not ready after retries (last code: ${code:-none})" >&2
|
||||
exit 1
|
||||
args:
|
||||
executable: /bin/bash
|
||||
changed_when: false
|
||||
register: acp_opencode_adapter_probe
|
||||
rescue:
|
||||
- name: Capture OpenCode ACP service status on failure
|
||||
ansible.builtin.command: systemctl status "{{ acp_opencode_service_name }}" --no-pager --full
|
||||
register: acp_opencode_status_fail
|
||||
changed_when: false
|
||||
failed_when: false
|
||||
when: ansible_os_family != 'Darwin'
|
||||
|
||||
- name: Capture recent OpenCode ACP service logs on failure
|
||||
ansible.builtin.command: journalctl -u "{{ acp_opencode_service_name }}" -n 80 --no-pager
|
||||
register: acp_opencode_journal_fail
|
||||
changed_when: false
|
||||
failed_when: false
|
||||
when: ansible_os_family != 'Darwin'
|
||||
|
||||
- name: Show OpenCode ACP failure diagnostics
|
||||
ansible.builtin.debug:
|
||||
msg:
|
||||
- "Probe stderr: {{ acp_opencode_adapter_probe.stderr | default('N/A') }}"
|
||||
- "Listeners: {{ acp_opencode_ss.stdout | default('N/A') }}"
|
||||
- "Service status: {{ acp_opencode_status_fail.stdout | default('N/A') }}"
|
||||
- "Recent logs: {{ acp_opencode_journal_fail.stdout | default('N/A') }}"
|
||||
|
||||
- name: Fail after emitting OpenCode ACP diagnostics
|
||||
ansible.builtin.fail:
|
||||
msg: >-
|
||||
OpenCode ACP endpoint
|
||||
{{ acp_opencode_listen_host }}:{{ acp_opencode_listen_port }} did not
|
||||
become ready. See the diagnostics above (service status + journal) for
|
||||
the adapter crash cause.
|
||||
|
||||
- name: Show OpenCode ACP status
|
||||
ansible.builtin.command: systemctl status "{{ acp_opencode_service_name }}" --no-pager
|
||||
register: acp_opencode_status
|
||||
changed_when: false
|
||||
failed_when: false
|
||||
when: ansible_os_family != 'Darwin'
|
||||
|
||||
- name: Show OpenCode ACP validation summary
|
||||
ansible.builtin.debug:
|
||||
@ -55,6 +90,6 @@
|
||||
- "Preferred WebSocket endpoint: {{ acp_opencode_public_base_url }}/acp"
|
||||
- "Compatibility HTTP RPC endpoint: {{ acp_opencode_public_base_url }}/acp/rpc"
|
||||
- "OpenCode ACP adapter listener: {{ acp_opencode_listen_host }}:{{ acp_opencode_listen_port }}"
|
||||
- "Readiness probe: {{ acp_opencode_adapter_probe.stdout | default('N/A') }}"
|
||||
- "Service: {{ acp_opencode_status.stdout | default('N/A') }}"
|
||||
- "Socket: {{ acp_opencode_ss.stdout | default('N/A') }}"
|
||||
- "Adapter capabilities HTTP: {{ acp_opencode_adapter_http.content | default('N/A') }}"
|
||||
|
||||
@ -9,9 +9,10 @@ User={{ acp_opencode_service_user }}
|
||||
Group={{ acp_opencode_service_group }}
|
||||
WorkingDirectory={{ acp_opencode_workdir }}
|
||||
Environment=HOME={{ acp_opencode_home }}
|
||||
Environment=PATH={{ acp_opencode_path }}
|
||||
Environment=TERM=xterm-256color
|
||||
Environment=OPENCODE_ADAPTER_ALLOWED_ORIGINS={{ acp_opencode_bridge_allowed_origins | join(',') }}
|
||||
ExecStart={{ acp_opencode_bridge_binary_path }} adapter opencode --listen {{ acp_opencode_listen_host }}:{{ acp_opencode_listen_port }} --opencode-bin /usr/bin/opencode --cwd {{ acp_opencode_workdir }}
|
||||
ExecStart={{ acp_opencode_bridge_binary_path }} adapter opencode --listen {{ acp_opencode_listen_host }}:{{ acp_opencode_listen_port }} --opencode-bin {{ acp_opencode_binary_path }} --cwd {{ acp_opencode_workdir }}
|
||||
Restart=always
|
||||
RestartSec=2
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user