tep 0.11.4 → 0.11.5

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.
data/lib/tep/presence.rb CHANGED
@@ -265,325 +265,29 @@ module Tep
265
265
  swept
266
266
  end
267
267
 
268
- # ---- PG mirror (cross-worker visibility) ----
269
- #
270
- # Opt-in mirror of the local presence registry to a shared PG
271
- # table. Each worker's track/untrack/set_status writes also
272
- # touch the table; list_global / count_global read across all
273
- # workers. The local registry stays the fast read path for
274
- # per-worker queries (list / count); list_global is for the
275
- # "who's globally in this room" snapshot that's typically a
276
- # one-shot UI render.
277
- #
278
- # Worker ID is PID + boot epoch second so a same-PID restart
279
- # doesn't alias a prior worker's stale rows. On
280
- # disable_pg_mirror (or clean shutdown), this worker's rows
281
- # get DELETE'd. Crashed workers leave stale rows; the
282
- # heartbeat + prune_stale_workers pair below handles the
283
- # garbage-collection.
284
- #
285
- # Returns 0 on success, -1 on connect / schema failure.
286
- def self.enable_pg_mirror(conninfo)
287
- conn = PG::Connection.new(conninfo)
288
- if conn.pgh < 0
289
- return -1
290
- end
291
- # exec raises PG::Error on failure now; degrade gracefully
292
- # (close + return -1) rather than letting it escape the worker.
293
- begin
294
- r = conn.exec(Tep::Presence.schema_sql)
295
- r.clear
296
- # Heartbeat table for the prune-stale-workers path (#47).
297
- r = conn.exec(Tep::Presence.worker_schema_sql)
298
- r.clear
299
- rescue PG::Error
300
- conn.finish
301
- return -1
302
- end
303
- Tep::APP.set_presence_pg_conn(conn)
304
- worker_id = Sock.sphttp_getpid.to_s + "-" + Time.now.to_i.to_s
305
- Tep::APP.set_presence_pg_worker_id(worker_id)
306
- Tep::APP.set_presence_pg_enabled(1)
307
- # Drop any rows from a prior worker that managed to leave
308
- # stale entries with this same worker_id (unlikely thanks
309
- # to the boot-epoch suffix, but defensive). Best-effort.
310
- Tep::Presence.mirror_exec(
311
- "DELETE FROM tep_presence WHERE worker_id = $1",
312
- [worker_id])
313
- # Register this worker's heartbeat row immediately. Apps
314
- # refresh it periodically via Tep::Presence.heartbeat;
315
- # prune_stale_workers deletes rows whose heartbeat is stale.
316
- Tep::Presence.heartbeat
317
- 0
318
- end
319
-
320
- def self.disable_pg_mirror
321
- if Tep::APP.presence_pg_enabled == 0
322
- return 0
323
- end
324
- # Best-effort cleanup -- swallow PG errors (we're tearing the
325
- # mirror down regardless) and still finish + disable below.
326
- begin
327
- r = Tep::APP.presence_pg_conn.exec_params(
328
- "DELETE FROM tep_presence WHERE worker_id = $1",
329
- [Tep::APP.presence_pg_worker_id])
330
- r.clear
331
- # Remove the heartbeat row so prune_stale_workers doesn't
332
- # see this worker as live after we're gone.
333
- r = Tep::APP.presence_pg_conn.exec_params(
334
- "DELETE FROM tep_presence_worker WHERE worker_id = $1",
335
- [Tep::APP.presence_pg_worker_id])
336
- r.clear
337
- rescue PG::Error
338
- # swallow -- shutting the mirror down anyway
339
- end
340
- Tep::APP.presence_pg_conn.finish
341
- Tep::APP.set_presence_pg_enabled(0)
342
- 0
343
- end
344
-
345
- # CREATE TABLE statement, kept here so apps that want to
346
- # provision the schema separately (migration runners, etc.)
347
- # can grab the canonical DDL. Idempotent via IF NOT EXISTS.
348
- def self.schema_sql
349
- "CREATE TABLE IF NOT EXISTS tep_presence (" +
350
- "worker_id TEXT NOT NULL, " +
351
- "topic TEXT NOT NULL, " +
352
- "fd INTEGER NOT NULL, " +
353
- "principal_id TEXT NOT NULL, " +
354
- "kind TEXT NOT NULL, " +
355
- "agent_id TEXT NOT NULL, " +
356
- "since_ts BIGINT NOT NULL, " +
357
- "status_state TEXT NOT NULL, " +
358
- "status_note TEXT NOT NULL, " +
359
- "status_until BIGINT NOT NULL, " +
360
- "PRIMARY KEY (worker_id, topic, fd)" +
361
- ")"
362
- end
363
-
364
- # Heartbeat table -- one row per worker that's mirroring
365
- # presence right now. Used by prune_stale_workers to identify
366
- # crashed workers (no heartbeat updates in N seconds) and
367
- # garbage-collect their orphan tep_presence rows.
368
- def self.worker_schema_sql
369
- "CREATE TABLE IF NOT EXISTS tep_presence_worker (" +
370
- "worker_id TEXT PRIMARY KEY, " +
371
- "last_seen_ts BIGINT NOT NULL" +
372
- ")"
373
- end
374
-
375
- # Refresh this worker's heartbeat row to the current Unix
376
- # timestamp. Apps call this periodically (typical: from a
377
- # before-filter, a Tep::Job tick, or an explicit timer fiber)
378
- # so prune_stale_workers can tell live workers from crashed
379
- # ones. No-op when the PG mirror isn't enabled, or when the
380
- # mirror was opened on a different process and we're the
381
- # post-fork child (worker_id is empty until enable_pg_mirror
382
- # runs locally).
383
- #
384
- # Returns 1 if the heartbeat row was upserted, 0 if the call
385
- # short-circuited (mirror disabled or no worker_id).
386
- def self.heartbeat
387
- if Tep::APP.presence_pg_enabled == 0
388
- return 0
389
- end
390
- wid = Tep::APP.presence_pg_worker_id
391
- if wid.length == 0
392
- return 0
393
- end
394
- begin
395
- r = Tep::APP.presence_pg_conn.exec_params(
396
- "INSERT INTO tep_presence_worker (worker_id, last_seen_ts) " +
397
- "VALUES ($1, $2) " +
398
- "ON CONFLICT (worker_id) DO UPDATE SET " +
399
- " last_seen_ts = EXCLUDED.last_seen_ts",
400
- [wid, Time.now.to_i.to_s])
401
- r.clear
402
- rescue PG::Error
403
- return 0
404
- end
405
- 1
406
- end
407
-
408
- # Prune crashed-worker rows. Deletes:
409
- # 1. tep_presence_worker rows whose last_seen_ts is older than
410
- # ttl_seconds (the worker's heartbeat is stale).
411
- # 2. tep_presence rows whose worker_id has no surviving
412
- # heartbeat (orphans left by the crashed worker).
413
- #
414
- # Apps call this periodically -- the canonical shape is a
415
- # before-filter on a "/health" route that internal monitoring
416
- # hits every 30s, or a Tep::Job that fires from a cron-like
417
- # tick. Returns the number of tep_presence rows deleted.
418
- #
419
- # ttl_seconds should be at least 3x the app's typical
420
- # heartbeat interval so a transient slow response doesn't
421
- # evict a live worker. Default callers pass 90 (assumes 30s
422
- # heartbeats).
423
- def self.prune_stale_workers(ttl_seconds)
424
- if Tep::APP.presence_pg_enabled == 0
425
- return 0
426
- end
427
- cutoff = Time.now.to_i - ttl_seconds
428
- conn = Tep::APP.presence_pg_conn
429
- begin
430
- # Drop dead heartbeats first; the second DELETE then walks
431
- # the worker_id space that's still alive.
432
- r1 = conn.exec_params(
433
- "DELETE FROM tep_presence_worker WHERE last_seen_ts < $1",
434
- [cutoff.to_s])
435
- r1.clear
436
- # Now drop presence rows whose worker_id isn't in the live
437
- # heartbeat table. NOT IN handles both crashed-and-pruned
438
- # workers and workers that never registered (legacy rows
439
- # from before this prune feature shipped).
440
- r2 = conn.exec(
441
- "DELETE FROM tep_presence " +
442
- "WHERE worker_id NOT IN (SELECT worker_id FROM tep_presence_worker)")
443
- n = r2.cmd_tuples
444
- r2.clear
445
- rescue PG::Error
446
- return 0
447
- end
448
- n
449
- end
450
-
451
- # Best-effort mirror write: run an exec_params on the mirror conn
452
- # and swallow any PG::Error. The PG mirror is advisory -- local
453
- # presence is authoritative -- so a transient mirror failure must
454
- # never propagate into the caller's request now that exec raises
455
- # (matz/spinel#627 + #1041). Always returns 0.
456
- def self.mirror_exec(sql, params)
457
- begin
458
- r = Tep::APP.presence_pg_conn.exec_params(sql, params)
459
- r.clear
460
- rescue PG::Error
461
- # swallow -- advisory mirror, local presence is authoritative
462
- end
463
- 0
464
- end
465
-
466
- # Mirror a track to PG. Called from track() when the PG
467
- # mirror is enabled.
468
- def self.mirror_insert(entry)
469
- if Tep::APP.presence_pg_enabled == 0
470
- return 0
471
- end
472
- Tep::Presence.mirror_exec(
473
- "INSERT INTO tep_presence " +
474
- "(worker_id, topic, fd, principal_id, kind, agent_id, " +
475
- " since_ts, status_state, status_note, status_until) " +
476
- "VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10) " +
477
- "ON CONFLICT (worker_id, topic, fd) DO UPDATE SET " +
478
- " principal_id = EXCLUDED.principal_id, " +
479
- " kind = EXCLUDED.kind, " +
480
- " agent_id = EXCLUDED.agent_id, " +
481
- " since_ts = EXCLUDED.since_ts, " +
482
- " status_state = EXCLUDED.status_state, " +
483
- " status_note = EXCLUDED.status_note, " +
484
- " status_until = EXCLUDED.status_until",
485
- [
486
- Tep::APP.presence_pg_worker_id,
487
- entry.topic,
488
- entry.fd.to_s,
489
- entry.principal_id,
490
- entry.kind.to_s,
491
- entry.agent_id,
492
- entry.since.to_s,
493
- entry.status_state.to_s,
494
- entry.status_note,
495
- entry.status_until.to_s
496
- ])
497
- end
498
-
499
- # Mirror an untrack to PG.
500
- def self.mirror_delete(topic, fd)
501
- if Tep::APP.presence_pg_enabled == 0
502
- return 0
503
- end
504
- Tep::Presence.mirror_exec(
505
- "DELETE FROM tep_presence " +
506
- "WHERE worker_id = $1 AND topic = $2 AND fd = $3",
507
- [Tep::APP.presence_pg_worker_id, topic, fd.to_s])
508
- end
509
-
510
- # Mirror a status update.
511
- def self.mirror_status(topic, fd, state, note, until_ts)
512
- if Tep::APP.presence_pg_enabled == 0
513
- return 0
514
- end
515
- Tep::Presence.mirror_exec(
516
- "UPDATE tep_presence " +
517
- "SET status_state = $4, status_note = $5, status_until = $6 " +
518
- "WHERE worker_id = $1 AND topic = $2 AND fd = $3",
519
- [Tep::APP.presence_pg_worker_id, topic, fd.to_s,
520
- state.to_s, note, until_ts.to_s])
521
- end
268
+ # ---- PG mirror (cross-worker visibility) ----
269
+ #
270
+ # The presence PG mirror is OPT-IN (#216). enable_pg_mirror /
271
+ # disable_pg_mirror / heartbeat / prune_stale_workers / mirror_exec /
272
+ # list_global / count_global / the schema DDL, and the REAL bodies of
273
+ # the mirror_* hooks below, live in lib/tep/pg.rb and only compile
274
+ # into apps that `require "tep/pg"`. Core Presence keeps no PG
275
+ # reference, so a non-PG app DCEs the libpq closure entirely.
276
+ #
277
+ # track / untrack / set_status call these mirror_* hooks
278
+ # unconditionally; the core definitions are no-ops. `require
279
+ # "tep/pg"` redefines them (last-definition-wins) with the real
280
+ # exec_params writes.
281
+ def self.mirror_insert(entry)
282
+ 0
283
+ end
522
284
 
523
- # Cross-worker list: SELECT all entries on `topic` regardless
524
- # of which worker tracked them. Returns Array[PresenceEntry]
525
- # built from the PG rows. The returned entries are read-only
526
- # snapshots -- mutating them doesn't write back to PG.
527
- def self.list_global(topic)
528
- result = [Tep::PresenceEntry.new("", "", :human, "", -1, 0)]
529
- result.delete_at(0)
530
- if Tep::APP.presence_pg_enabled == 0
531
- return result
532
- end
533
- begin
534
- r = Tep::APP.presence_pg_conn.exec_params(
535
- "SELECT principal_id, kind, agent_id, fd, since_ts, " +
536
- " status_state, status_note, status_until " +
537
- "FROM tep_presence WHERE topic = $1 ORDER BY since_ts",
538
- [topic])
539
- rescue PG::Error
540
- return result
541
- end
542
- i = 0
543
- n = r.ntuples
544
- while i < n
545
- kind_sym = :human
546
- if r.getvalue(i, 1) == "agent_for"
547
- kind_sym = :agent_for
548
- end
549
- state_sym = :available
550
- sstr = r.getvalue(i, 5)
551
- if sstr == "busy"
552
- state_sym = :busy
553
- elsif sstr == "blocked"
554
- state_sym = :blocked
555
- end
556
- e = Tep::PresenceEntry.new(
557
- topic,
558
- r.getvalue(i, 0),
559
- kind_sym,
560
- r.getvalue(i, 2),
561
- r.getvalue(i, 3).to_i,
562
- r.getvalue(i, 4).to_i)
563
- e.status_state = state_sym
564
- e.status_note = r.getvalue(i, 6)
565
- e.status_until = r.getvalue(i, 7).to_i
566
- result.push(e)
567
- i += 1
568
- end
569
- r.clear
570
- result
571
- end
285
+ def self.mirror_delete(topic, fd)
286
+ 0
287
+ end
572
288
 
573
- def self.count_global(topic)
574
- if Tep::APP.presence_pg_enabled == 0
575
- return 0
576
- end
577
- begin
578
- r = Tep::APP.presence_pg_conn.exec_params(
579
- "SELECT count(*) FROM tep_presence WHERE topic = $1",
580
- [topic])
581
- rescue PG::Error
582
- return 0
583
- end
584
- n = r.getvalue(0, 0).to_i
585
- r.clear
586
- n
587
- end
289
+ def self.mirror_status(topic, fd, state, note, until_ts)
290
+ 0
291
+ end
588
292
  end
589
293
  end
data/lib/tep/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Tep
2
- VERSION = "0.11.4"
2
+ VERSION = "0.11.5"
3
3
  end
data/lib/tep.rb CHANGED
@@ -70,7 +70,10 @@ require_relative "tep/live_view"
70
70
  require_relative "tep/server"
71
71
  require_relative "tep/server_scheduled"
72
72
  require_relative "tep/sqlite"
73
- require_relative "tep/pg"
73
+ # tep/pg is OPT-IN (#216): NOT required here. An app that needs
74
+ # PostgreSQL does `require "tep/pg"`, which bin/tep splices in at build
75
+ # time (and the test suite requires explicitly). Keeping it out of the
76
+ # core require tree is what lets a non-PG app DCE the libpq closure.
74
77
  require_relative "spinel_kit/json"
75
78
  require_relative "spinel_kit/json_decoder"
76
79
  require_relative "tep/mcp"
@@ -213,13 +216,7 @@ module Tep
213
216
  APP.set_after(Filter.new)
214
217
  APP.set_auth_filter(Filter.new)
215
218
  APP.set_auth_bearer_secret("")
216
- # Broadcast PG-backend setter seeds. enable_pg_backend reaches
217
- # these via set_broadcast_pg_conn / _channel / _enabled when a
218
- # connect succeeds; the empty-conninfo seed below short-circuits
219
- # before getting there, so we exercise the setters directly.
220
- APP.set_broadcast_pg_enabled(0)
221
- APP.set_broadcast_pg_channel("")
222
- APP.set_broadcast_pg_conn(PG::Connection.new(""))
219
+ # (broadcast_pg setter seeds relocated to lib/tep/pg.rb -- #216)
223
220
  APP.set_not_found(Handler.new)
224
221
  # Type-seeding: methods that may not be called by a given user app
225
222
  # would otherwise default their param C types to mrb_int and
@@ -275,19 +272,10 @@ module Tep
275
272
  Tep::Broadcast.subscriber_count
276
273
  Tep::Broadcast.clear
277
274
 
278
- # Broadcast PG-backend seeds. enable_pg_backend("", "") tries to
279
- # open a PG connection -- empty conninfo behaves the same as the
280
- # PG::Connection.new("") seed above: connect fails, returns -1.
281
- # The point is to pin parameter types on every cmeth.
282
- Tep::Broadcast.enable_pg_backend("", "")
283
- Tep::Broadcast.poll_pg_once(0)
284
- Tep::Broadcast.disable_pg_backend
285
- Tep::Broadcast.encode_wire("", "")
286
- Tep::Broadcast.deliver_wire_local("0:")
287
275
  Tep::Broadcast.publish_local_only("_seed", "")
288
- # The new PG::Connection LISTEN/NOTIFY method seeds live further
289
- # down with the rest of the PG seeds, where _tep_seed_pg_conn is
290
- # already defined.
276
+ # (Broadcast PG-backend seeds -- enable_pg_backend / poll_pg_once /
277
+ # disable_pg_backend / encode_wire / deliver_wire_local -- relocated
278
+ # to lib/tep/pg.rb, #216.)
291
279
 
292
280
  # Presence type-seeding. Same pattern as Broadcast: pin every
293
281
  # cmeth's param C types so compile units that don't otherwise
@@ -317,25 +305,10 @@ module Tep
317
305
  Tep::Presence.encode_diff("join", _tep_seed_presence_entry)
318
306
  Tep::Presence.publish_diff("join", _tep_seed_presence_entry)
319
307
  Tep::Presence.sweep_expired_status
320
- # PG mirror seeds (chunk 3.3). enable_pg_mirror("") fails the
321
- # connect cleanly (-1) but still pins param types.
322
- Tep::Presence.enable_pg_mirror("")
323
- Tep::Presence.schema_sql
324
- Tep::Presence.mirror_insert(_tep_seed_presence_entry)
325
- Tep::Presence.mirror_delete("_seed", -1)
326
- Tep::Presence.mirror_status("_seed", -1, :available, "", 0)
327
- Tep::Presence.list_global("_seed")
328
- Tep::Presence.count_global("_seed")
329
- Tep::Presence.worker_schema_sql
330
- Tep::Presence.heartbeat
331
- Tep::Presence.prune_stale_workers(90)
332
- Tep::Presence.disable_pg_mirror
333
- # Same APP-setter-via-constant pattern as the broadcast_pg_conn
334
- # seed: PG::Connection.new can't run inside App#initialize
335
- # (Tep::APP is mid-construction; sched_current read segfaults).
336
- APP.set_presence_pg_enabled(0)
337
- APP.set_presence_pg_worker_id("")
338
- APP.set_presence_pg_conn(PG::Connection.new(""))
308
+ # (Presence PG mirror seeds + presence_pg setter seeds relocated to
309
+ # lib/tep/pg.rb -- #216. The core mirror_insert/delete/status no-op
310
+ # stubs are already seeded by the track/set_status/untrack calls
311
+ # above.)
339
312
 
340
313
  # LiveView type-seeding (chunk 4.1). The render_page + dispatch_event
341
314
  # cmeths get pinned via top-level calls; the base-class mount /
@@ -387,72 +360,9 @@ module Tep
387
360
  _tep_seed_db.close
388
361
  end
389
362
 
390
- # PG type-seeding. PG::Connection.new("") returns a connection-
391
- # failed instance (@pgh=-1) rather than raising, so this is safe
392
- # at module load regardless of whether libpq has a reachable
393
- # server. The point is to pin parameter / return types on every
394
- # public Connection / Result method so apps that don't exercise
395
- # one method still compile cleanly.
396
- _tep_seed_pg_conn = PG::Connection.new("")
397
- _tep_seed_pg_conn.connected?
398
- _tep_seed_pg_conn.status
399
- _tep_seed_pg_conn.transaction_status
400
- _tep_seed_pg_conn.server_version
401
- _tep_seed_pg_conn.error_message
402
- _tep_seed_pg_conn.escape_string("")
403
- _tep_seed_pg_conn.escape_identifier("")
404
- _tep_seed_pg_conn.escape_literal("")
405
- _tep_seed_pg_conn.last_sqlstate = ""
406
- _tep_seed_pg_conn.last_error_message = ""
407
- _tep_seed_pg_conn.last_result_rh = -1
408
- # Async surface seed -- calling these on a failed-conn instance
409
- # is harmless (the C shim short-circuits on conn slot < 1).
410
- _tep_seed_pg_conn.async_exec("")
411
- _tep_seed_pg_seed_arr = [""]
412
- _tep_seed_pg_seed_arr.delete_at(0)
413
- _tep_seed_pg_conn.async_exec_params("", _tep_seed_pg_seed_arr)
414
- # Async connect cmeth. Returns -1 for empty conninfo from a
415
- # non-scheduled context (the shim's PQconnectStart-then-FAILED
416
- # path), which is type-equivalent to the success path.
417
- PG::Connection.async_connect("")
418
- # LISTEN / NOTIFY surface (Tep::Broadcast PG backend lands here).
419
- _tep_seed_pg_conn.listen("_seed")
420
- _tep_seed_pg_conn.unlisten("_seed")
421
- _tep_seed_pg_conn.notify("_seed", "")
422
- _tep_seed_pg_conn.poll_notification(0)
423
- _tep_seed_pg_conn.last_notify_channel
424
- _tep_seed_pg_conn.last_notify_payload
425
- _tep_seed_pg_res = PG::Result.new(-1)
426
- _tep_seed_pg_res.ntuples
427
- _tep_seed_pg_res.nfields
428
- _tep_seed_pg_res.fname(0)
429
- _tep_seed_pg_res.fnumber("")
430
- _tep_seed_pg_res.ftype(0)
431
- _tep_seed_pg_res.fformat(0)
432
- _tep_seed_pg_res.fmod(0)
433
- _tep_seed_pg_res.getvalue(0, 0)
434
- _tep_seed_pg_res.getisnull(0, 0)
435
- _tep_seed_pg_res.getlength(0, 0)
436
- _tep_seed_pg_res.value(0, 0)
437
- _tep_seed_pg_res.error_field(67)
438
- _tep_seed_pg_res.cmd_status
439
- _tep_seed_pg_res.cmd_tuples
440
- _tep_seed_pg_res.error_message
441
- _tep_seed_pg_res.sql_state
442
- _tep_seed_pg_res.fields
443
- _tep_seed_pg_res.values
444
- _tep_seed_pg_res.column_values(0)
445
- _tep_seed_pg_res.clear
446
- _tep_seed_pg_conn.close
447
- # Pool seed -- size 0 so we don't try to open real conns at load.
448
- _tep_seed_pg_pool = PG::Pool.new("", 0)
449
- _tep_seed_pg_pool.healthy?
450
- _tep_seed_pg_pool.available
451
- _tep_seed_pg_pool.size
452
- _tep_seed_pg_pool.set_checkout_timeout_ms(0)
453
- _tep_seed_pg_pool.close_all
454
- # NB: don't checkout/checkin against the size-0 seed pool; it'd
455
- # spin until timeout. The seed has @free.length=0 forever.
363
+ # (PG::Connection / Result / Pool type-seeding relocated to
364
+ # lib/tep/pg.rb -- #216. PG.Connection.new("") is a failed-conn
365
+ # instance, not a raise, so the seeds stay safe at module load.)
456
366
 
457
367
  # SpinelKit::Json type-seeding. Pin every public method's parameter
458
368
  # types so an app that uses one method but not another still
@@ -539,10 +449,19 @@ module Tep
539
449
  Tep::Scheduler.clear
540
450
 
541
451
  # Tep::Shell seed -- pin :str args at the FFI boundary.
452
+ #
453
+ # These run at MODULE LOAD, so the paths must be readable in EVERY
454
+ # deploy environment, not just gx10. `/etc/hostname` is absent in a
455
+ # bare container (e.g. Upsun); under the engine's now-correct
456
+ # ENOENT-raising File.read it threw at boot and 502'd the native
457
+ # serve_bin (tep#199 boot-hazard report). `/dev/null` exists on every
458
+ # POSIX target (Linux containers, macOS) and reads as empty, so it
459
+ # pins the same :str param type without the missing-file crash. The
460
+ # full fix -- no boot-time seed I/O at all -- is tep#199 (--rbs sig).
542
461
  Tep::Shell.run(":")
543
462
  Tep::Shell.run_limited(":", 1)
544
- Tep::Shell.read("/etc/hostname")
545
- Tep::Shell.read_limited("/etc/hostname", 64)
463
+ Tep::Shell.read("/dev/null")
464
+ Tep::Shell.read_limited("/dev/null", 64)
546
465
 
547
466
  # SpinelKit::Url seed -- the new split_url has to land at compile time.
548
467
  SpinelKit::Url.split_url("http://x/")
data/spinel-ext.json CHANGED
@@ -5,6 +5,12 @@
5
5
  "source": "lib/tep/sphttp.c",
6
6
  "cflags": ["-O2"]
7
7
  },
8
+ {
9
+ "name": "sphttp",
10
+ "placeholder": "@TEP_SPHTTP_CFLAGS@",
11
+ "pkg_config": "openssl",
12
+ "pkg_config_fallback": "-lssl -lcrypto"
13
+ },
8
14
  {
9
15
  "name": "sqlite",
10
16
  "placeholder": "@TEP_SQLITE_O@",
@@ -18,6 +18,7 @@ class TestBroadcastPg < TepTest
18
18
 
19
19
  app_source <<~RB
20
20
  require 'sinatra'
21
+ require "tep/pg" # opt-in PG backend (#216)
21
22
 
22
23
  PG_URL = "#{PG_URL}"
23
24
  CHANNEL = "#{CHANNEL}"
data/test/test_pg.rb CHANGED
@@ -42,6 +42,7 @@ class TestPg < TepTest
42
42
  # in the compiled binary.
43
43
  app_source <<~RB
44
44
  require 'sinatra'
45
+ require "tep/pg" # opt-in PG backend (#216)
45
46
 
46
47
  # The PG test app runs under the default prefork server. We
47
48
  # exercise the async surface explicitly via /async_exec and
@@ -29,6 +29,7 @@ class TestPresencePg < TepTest
29
29
 
30
30
  app_source <<~RB
31
31
  require 'sinatra'
32
+ require "tep/pg" # opt-in PG backend (#216)
32
33
 
33
34
  PG_URL = "#{PG_URL}"
34
35
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tep
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.11.4
4
+ version: 0.11.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ori Pekelman
@@ -23,6 +23,20 @@ dependencies:
23
23
  - - "~>"
24
24
  - !ruby/object:Gem::Version
25
25
  version: '1.0'
26
+ - !ruby/object:Gem::Dependency
27
+ name: spinel_kit
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - "~>"
31
+ - !ruby/object:Gem::Version
32
+ version: '0.2'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '0.2'
26
40
  description: |-
27
41
  tep is a small Sinatra-style DSL targeting the Spinel AOT Ruby
28
42
  compiler. The translator turns a Sinatra-classic source file into