1818//! - `GITEA_TOKEN` fallback for `RUNNER_STATUS_TOKEN` when unset
1919//! - `RUNNER_CHECKOUT_DIR` checkout root; per-repo trees at `<root>/<owner>/<repo>` (default `.`)
2020//! - `RUNNER_HTTP_TIMEOUT` per-request HTTP timeout in seconds (default 30)
21+ //! - `RUNNER_POLL_TIMEOUT` belt-and-suspenders timeout wrapping a single
22+ //! fetch/execute iteration in seconds (default 7200). Must exceed the longest
23+ //! expected workflow step; the workflow executor has its own per-step timeout.
2124//! - `RUNNER_TAXONOMY_DIR` directory containing `command_policy.md` for the
2225//! command allowlist; if unset, the embedded default policy is used
2326
@@ -72,6 +75,17 @@ async fn main() -> anyhow::Result<()> {
7275 . unwrap_or ( 30 ) ;
7376 let http_request_timeout = Duration :: from_secs ( http_timeout_secs) ;
7477
78+ // #2185 / #2971: the poll timeout wraps the entire FetchTask + workflow
79+ // execution iteration. The previous default (http_timeout * 2 = 60s) was
80+ // shorter than terraphim-ai build/test steps, causing the runner to abort
81+ // long-running but healthy jobs. Default to 2h to match the workflow
82+ // executor's max_execution_time; operators can tune via env.
83+ let poll_timeout_secs: u64 = std:: env:: var ( "RUNNER_POLL_TIMEOUT" )
84+ . ok ( )
85+ . and_then ( |v| v. parse ( ) . ok ( ) )
86+ . unwrap_or ( 7200 ) ;
87+ let poll_timeout = Duration :: from_secs ( poll_timeout_secs) ;
88+
7589 let status_token = std:: env:: var ( "RUNNER_STATUS_TOKEN" )
7690 . ok ( )
7791 . or_else ( || std:: env:: var ( "GITEA_TOKEN" ) . ok ( ) ) ;
@@ -89,7 +103,7 @@ async fn main() -> anyhow::Result<()> {
89103 legacy_status_mirror,
90104 status_token,
91105 http_request_timeout,
92- poll_timeout : Duration :: from_secs ( http_timeout_secs * 2 ) ,
106+ poll_timeout,
93107 taxonomy_dir,
94108 } ;
95109 let checkout_dir = env_or ( "RUNNER_CHECKOUT_DIR" , "." ) ;
0 commit comments