|
1 | 1 | import { spawn } from "node:child_process"; |
| 2 | +import { randomUUID } from "node:crypto"; |
2 | 3 | import { createWriteStream } from "node:fs"; |
3 | 4 | import * as fs from "node:fs/promises"; |
4 | 5 | import * as path from "node:path"; |
@@ -103,9 +104,11 @@ export async function ensureEngineProcess( |
103 | 104 |
|
104 | 105 | child.once("exit", (code, signal) => { |
105 | 106 | logger().warn({ |
106 | | - msg: "engine process exited", |
| 107 | + msg: "engine process exited, please report this error", |
107 | 108 | code, |
108 | 109 | signal, |
| 110 | + issues: "https://github.com/rivet-dev/rivetkit/issues", |
| 111 | + support: "https://rivet.dev/discord", |
109 | 112 | }); |
110 | 113 | // Clean up log streams |
111 | 114 | stdoutStream.end(); |
@@ -168,22 +171,70 @@ async function downloadEngineBinaryIfNeeded( |
168 | 171 | ); |
169 | 172 | } |
170 | 173 |
|
171 | | - const tempPath = `${binaryPath}.${process.pid}.tmp`; |
172 | | - await pipeline(response.body, createWriteStream(tempPath)); |
173 | | - if (process.platform !== "win32") { |
174 | | - await fs.chmod(tempPath, 0o755); |
175 | | - } |
176 | | - await fs.rename(tempPath, binaryPath); |
| 174 | + // Generate unique temp file name to prevent parallel download conflicts |
| 175 | + const tempPath = `${binaryPath}.${randomUUID()}.tmp`; |
| 176 | + const startTime = Date.now(); |
| 177 | + |
177 | 178 | logger().debug({ |
178 | | - msg: "engine binary download complete", |
179 | | - version, |
180 | | - path: binaryPath, |
181 | | - }); |
182 | | - logger().info({ |
183 | | - msg: "engine binary downloaded", |
184 | | - version, |
185 | | - path: binaryPath, |
| 179 | + msg: "starting binary download", |
| 180 | + tempPath, |
| 181 | + contentLength: response.headers.get("content-length"), |
186 | 182 | }); |
| 183 | + |
| 184 | + // Warn user if download is taking a long time |
| 185 | + const slowDownloadWarning = setTimeout(() => { |
| 186 | + logger().warn({ |
| 187 | + msg: "engine binary download is taking longer than expected, please be patient", |
| 188 | + version, |
| 189 | + }); |
| 190 | + }, 5000); |
| 191 | + |
| 192 | + try { |
| 193 | + await pipeline(response.body, createWriteStream(tempPath)); |
| 194 | + |
| 195 | + // Clear the slow download warning |
| 196 | + clearTimeout(slowDownloadWarning); |
| 197 | + |
| 198 | + // Get file size to verify download |
| 199 | + const stats = await fs.stat(tempPath); |
| 200 | + const downloadDuration = Date.now() - startTime; |
| 201 | + |
| 202 | + if (process.platform !== "win32") { |
| 203 | + await fs.chmod(tempPath, 0o755); |
| 204 | + } |
| 205 | + await fs.rename(tempPath, binaryPath); |
| 206 | + |
| 207 | + logger().debug({ |
| 208 | + msg: "engine binary download complete", |
| 209 | + version, |
| 210 | + path: binaryPath, |
| 211 | + size: stats.size, |
| 212 | + durationMs: downloadDuration, |
| 213 | + }); |
| 214 | + logger().info({ |
| 215 | + msg: "engine binary downloaded", |
| 216 | + version, |
| 217 | + path: binaryPath, |
| 218 | + }); |
| 219 | + } catch (error) { |
| 220 | + // Clear the slow download warning |
| 221 | + clearTimeout(slowDownloadWarning); |
| 222 | + |
| 223 | + // Clean up partial temp file on error |
| 224 | + logger().warn({ |
| 225 | + msg: "engine download failed, please report this error", |
| 226 | + tempPath, |
| 227 | + error, |
| 228 | + issues: "https://github.com/rivet-dev/rivetkit/issues", |
| 229 | + support: "https://rivet.dev/discord", |
| 230 | + }); |
| 231 | + try { |
| 232 | + await fs.unlink(tempPath); |
| 233 | + } catch (unlinkError) { |
| 234 | + // Ignore errors when cleaning up (file may not exist) |
| 235 | + } |
| 236 | + throw error; |
| 237 | + } |
187 | 238 | } |
188 | 239 |
|
189 | 240 | function resolveTargetTriplet(): { targetTriplet: string; extension: string } { |
|
0 commit comments