@dotrino/content 0.4.0 → 0.4.1

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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/announce.js +34 -3
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dotrino/content",
3
- "version": "0.4.0",
3
+ "version": "0.4.1",
4
4
  "description": "Nodo de contenido del ecosistema Dotrino: guarda los bytes del usuario direccionados por su hash (cid), en su propia maquina y, si el dueno quiere, respaldados en su propio bucket (R2, Backblaze, Hetzner, Storj o S3). Lo publico sale por URL directa; lo privado, cifrado y solo por la red Dotrino.",
5
5
  "type": "module",
6
6
  "bin": {
package/src/announce.js CHANGED
@@ -38,6 +38,21 @@ export { channelFor }
38
38
  /** Cada cuánto se re-publica (el proxio caduca las entradas de canal). */
39
39
  export const REPUBLISH_MS = 4 * 60 * 1000
40
40
 
41
+ /**
42
+ * Cada cuánto se reintenta un anuncio que falló. No se espera al tic de 4 min: el fallo
43
+ * típico es un proxio recién reiniciado (cada despliegue lo hace) cuya malla con el otro
44
+ * aún no está lista, y eso se arregla en segundos. Mientras tanto quien esté conectado a
45
+ * ese proxio no encuentra el node.
46
+ */
47
+ export const RETRY_MS = 30 * 1000
48
+
49
+ /**
50
+ * Cuántos reintentos seguidos se aguantan en silencio antes de llamarlo error (~2 min).
51
+ * Un proxio que se está reiniciando no es un fallo y no debe salir en el log de errores;
52
+ * uno que lleva dos minutos sin dejar anunciarse, sí.
53
+ */
54
+ export const FAILURES_BEFORE_ERROR = 4
55
+
41
56
  /**
42
57
  * Publica este node en el canal de su dueño, en todos los proxios conocidos, y lo
43
58
  * mantiene publicado. Best-effort a propósito: si el proxy está caído, el node
@@ -45,17 +60,19 @@ export const REPUBLISH_MS = 4 * 60 * 1000
45
60
  * siguiente tic lo vuelve a intentar. Un anuncio perdido no rompe nada; lo único
46
61
  * que pasa es que un tercero no lo encuentra hasta que vuelva.
47
62
  *
48
- * @param {{ client: any, owner: string, quiet?: boolean, intervalMs?: number }} opts
63
+ * @param {{ client: any, owner: string, quiet?: boolean, intervalMs?: number, retryMs?: number }} opts
49
64
  * client: el `WebSocketProxyClient` YA conectado del agente (`ra.client`) — no se
50
65
  * abre otro: dos conexiones del mismo aparato son dos identidades de transporte.
51
66
  * @returns {{ channels: () => string[], close: () => void }}
52
67
  */
53
- export function startAnnounce ({ client, owner, quiet = false, intervalMs = REPUBLISH_MS }) {
68
+ export function startAnnounce ({ client, owner, quiet = false, intervalMs = REPUBLISH_MS, retryMs = RETRY_MS }) {
54
69
  if (!client) throw new Error('startAnnounce: client is required')
55
70
  if (!owner) throw new Error('startAnnounce: owner is required')
56
71
 
57
72
  let stopped = false
58
73
  let current = []
74
+ let retry = null
75
+ const failures = new Map() // canal → fallos seguidos
59
76
 
60
77
  /** Los proxios donde hay que anunciarse: el que nos atiende y los que conoce. */
61
78
  const targets = () => {
@@ -72,10 +89,23 @@ export function startAnnounce ({ client, owner, quiet = false, intervalMs = REPU
72
89
  try {
73
90
  await client.publish(name, { app: 'content', owner })
74
91
  done.push(name)
92
+ const antes = failures.get(name) || 0
93
+ failures.delete(name)
94
+ if (antes >= FAILURES_BEFORE_ERROR && !quiet) console.log(`[content] announce on ${name} works again`)
75
95
  } catch (e) {
76
- if (!quiet) console.error(`[content] could not announce on ${name}: ${e.message}`)
96
+ const n = (failures.get(name) || 0) + 1
97
+ failures.set(name, n)
98
+ if (quiet) continue
99
+ // Primer fallo: casi siempre un proxio que se acaba de reiniciar. Se dice sin alarma.
100
+ if (n === 1) console.log(`[content] announce on ${name} failed (${e.message}); retrying every ${retryMs / 1000} s`)
101
+ // Si sigue, ya no es un reinicio: error, una sola vez hasta que se recupere.
102
+ else if (n === FAILURES_BEFORE_ERROR) console.error(`[content] still cannot announce on ${name} after ${Math.round(n * retryMs / 60000)} min: ${e.message}`)
77
103
  }
78
104
  }
105
+ if (failures.size && !retry && !stopped) {
106
+ retry = setTimeout(() => { retry = null; publishAll() }, retryMs)
107
+ retry.unref?.()
108
+ }
79
109
  // Se avisa cuando CAMBIA en cuántos proxios está anunciado, no solo la primera vez.
80
110
  // Antes solo hablaba al pasar de 0 a algo, así que un arranque que solo alcanzó uno de
81
111
  // los dos decía «en 1 proxio(s)» y se callaba para siempre — aunque el tic siguiente ya
@@ -98,6 +128,7 @@ export function startAnnounce ({ client, owner, quiet = false, intervalMs = REPU
98
128
  close () {
99
129
  stopped = true
100
130
  clearInterval(timer)
131
+ if (retry) { clearTimeout(retry); retry = null }
101
132
  try { offToken?.() } catch (_) {}
102
133
  for (const name of current) { try { client.unpublish(name) } catch (_) {} }
103
134
  current = []