@forgent3d/cad-runtime 0.1.6 → 0.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@forgent3d/cad-runtime",
3
- "version": "0.1.6",
3
+ "version": "0.1.7",
4
4
  "description": "Shared CAD runtime protocol, types, and pure utilities for Forgent3D cloud services.",
5
5
  "license": "MIT",
6
6
  "author": "Forgent3D",
@@ -318,6 +318,18 @@ def client_main(argv) -> int:
318
318
  return 3
319
319
 
320
320
 
321
+ # Written after warmup so a cheap files.exists() check (no python spawn) tells the
322
+ # cf-sandbox Worker the daemon is up. Keep in sync with SANDBOX_DAEMON_READY_MARKER.
323
+ READY_MARKER = "/tmp/.aicad-rebuild-daemon.ready"
324
+
325
+
326
+ def _remove_ready_marker() -> None:
327
+ try:
328
+ os.unlink(READY_MARKER)
329
+ except OSError:
330
+ pass
331
+
332
+
321
333
  def main() -> int:
322
334
  if len(sys.argv) > 1 and sys.argv[1] == "client":
323
335
  return client_main(sys.argv[2:])
@@ -327,13 +339,40 @@ def main() -> int:
327
339
  parser.add_argument("--port", type=int, default=8765)
328
340
  args = parser.parse_args()
329
341
 
342
+ # Bind FIRST so a duplicate launch (two prewarm/resolve calls racing) fails fast on
343
+ # the busy port instead of running a second ~2.2s warmup — the existing daemon keeps
344
+ # serving. The socket is listening immediately, so requests that arrive during warmup
345
+ # queue in the backlog and block until serve_forever() handles them — callers wait
346
+ # through warmup rather than being refused (and racing their own cold import).
347
+ try:
348
+ server = HTTPServer((args.host, args.port), Handler)
349
+ except OSError as exc:
350
+ print(f"[rebuild_daemon] port {args.port} busy ({exc}); another daemon owns it", file=sys.stderr)
351
+ return 0
352
+
330
353
  _warmup()
331
- server = HTTPServer((args.host, args.port), Handler)
354
+
355
+ import atexit
356
+ import signal
357
+ atexit.register(_remove_ready_marker)
358
+ for _sig in (signal.SIGTERM, signal.SIGINT):
359
+ try:
360
+ signal.signal(_sig, lambda *_: sys.exit(0))
361
+ except Exception:
362
+ pass
363
+ try:
364
+ with open(READY_MARKER, "w") as f:
365
+ f.write(str(os.getpid()))
366
+ except OSError:
367
+ pass
368
+
332
369
  print(f"[rebuild_daemon] ready on {args.host}:{args.port} pid={os.getpid()}", flush=True)
333
370
  try:
334
371
  server.serve_forever()
335
372
  except KeyboardInterrupt:
336
373
  pass
374
+ finally:
375
+ _remove_ready_marker()
337
376
  return 0
338
377
 
339
378