@certik/skynet 0.10.10 → 0.10.13

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/CHANGELOG.md CHANGED
@@ -1,5 +1,21 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.10.13
4
+
5
+ - Initialize Ably after user request publishing messages
6
+
7
+ - Increase wait time for Ably message sending bottleneck
8
+
9
+ - Update packages
10
+
11
+ ## 0.10.12
12
+
13
+ - Fixed distributed lock name for `producer` and `api` type apps
14
+
15
+ ## 0.10.11
16
+
17
+ - Added distributed lock for `producer` and `api` type apps
18
+
3
19
  ## 0.10.10
4
20
 
5
21
  - Updated `every` helper function in `app` library to support usage like `every(1).days` and `every(10).day`
package/ably.js CHANGED
@@ -2,12 +2,23 @@ const Ably = require("ably");
2
2
  const Bottleneck = require("bottleneck/es5");
3
3
  const { ensureAndGet } = require("./env");
4
4
 
5
- const ably = new Ably.Realtime(ensureAndGet("ABLY_ROOT_API_KEY"));
6
- ably.connection.on("connected", () => {
7
- console.log("ably connection successful");
8
- });
5
+ let ABLY;
6
+
7
+ async function getAbly() {
8
+ if (!ABLY) {
9
+ ABLY = await new Promise((resolve) => {
10
+ const ably = new Ably.Realtime(ensureAndGet("ABLY_ROOT_API_KEY"));
11
+ ably.connection.on("connected", () => {
12
+ console.log("ably connection successful");
13
+ resolve(ably);
14
+ });
15
+ });
16
+ }
17
+ return ABLY;
18
+ }
9
19
 
10
20
  async function publishMessage(channel, messageName, messageData) {
21
+ const ably = await getAbly();
11
22
  const channelObj = ably.channels.get(channel);
12
23
 
13
24
  const messageDataJson = JSON.stringify(messageData);
@@ -20,7 +31,7 @@ async function publishMessage(channel, messageName, messageData) {
20
31
  }
21
32
 
22
33
  const rateLimitedPublishMessage = new Bottleneck({
23
- minTime: 1000 / 50,
34
+ minTime: 1000 / 60,
24
35
  }).wrap(publishMessage);
25
36
 
26
37
  module.exports = {
package/api.js CHANGED
@@ -1,7 +1,8 @@
1
1
  const express = require("express");
2
2
  const meow = require("meow");
3
- const { getSelectorFlags, getSelectorDesc } = require("./selector");
3
+ const { getJobName, getSelectorFlags, getSelectorDesc } = require("./selector");
4
4
  const { isProduction } = require("./env");
5
+ const { useLock } = require("./distributed-lock");
5
6
  const { inline } = require("./log");
6
7
 
7
8
  async function logMiddleware(req, res, next) {
@@ -54,7 +55,7 @@ const apiKeyMiddleware = (key) => {
54
55
  return requireAPIKey;
55
56
  };
56
57
 
57
- function startApiApp({ binaryName, name, selector = {}, routes, serve }) {
58
+ async function startApiApp({ binaryName, name, selector = {}, routes, serve }) {
58
59
  const app = express();
59
60
  app.use(express.json());
60
61
 
@@ -82,6 +83,8 @@ ${getSelectorDesc(selector)}
82
83
 
83
84
  const { verbose, ...selectorFlags } = cli.flags;
84
85
 
86
+ await useLock({ name: getJobName(name, selectorFlags), ttl: 120, verbose });
87
+
85
88
  // for health check
86
89
  app.get("/", (req, res) => {
87
90
  res.send("ok");
package/app.js CHANGED
@@ -635,7 +635,7 @@ function api({ name, routes, serve, env = {}, region = "us-east-1" }) {
635
635
  env,
636
636
  check,
637
637
  onRun: () => {
638
- startApiApp({
638
+ return startApiApp({
639
639
  binaryName: `${getBinaryName()} run`,
640
640
  name,
641
641
  selector,
package/deploy.js CHANGED
@@ -4,7 +4,7 @@ const execa = require("execa");
4
4
  const meow = require("meow");
5
5
  const chalk = require("chalk");
6
6
  const which = require("which");
7
- const { getSelectorFlags, getSelectorDesc } = require("./selector");
7
+ const { getJobName, getSelectorFlags, getSelectorDesc } = require("./selector");
8
8
  const { getEnvOrThrow } = require("./env");
9
9
  const { getBinaryName, detectSkynetDirectory } = require("./cli");
10
10
 
@@ -207,30 +207,6 @@ EOH
207
207
  }
208
208
  }`;
209
209
 
210
- function normalizeSelectorValue(v) {
211
- return v.replace(/[^A-Za-z0-9]+/g, "-");
212
- }
213
-
214
- function getJobName(name, selectorFlags, mode = null) {
215
- const selectorNamePart = Object.keys(selectorFlags)
216
- .sort()
217
- .map((name) => selectorFlags[name])
218
- .join("-");
219
-
220
- let jobName = name;
221
-
222
- if (mode) {
223
- jobName += `-${mode}`;
224
- }
225
-
226
- if (selectorNamePart.length > 0) {
227
- // handle special case
228
- jobName += `-${normalizeSelectorValue(selectorNamePart)}`;
229
- }
230
-
231
- return jobName;
232
- }
233
-
234
210
  async function prepareNomad(isProduction) {
235
211
  if (isProduction) {
236
212
  console.log("Deploy to Production");
@@ -0,0 +1,113 @@
1
+ const fetch = require("node-fetch");
2
+
3
+ async function acquireLock(name, ttl) {
4
+ try {
5
+ const res = await fetch("http://localhost:8500/v1/session/create", {
6
+ method: "PUT",
7
+ body: JSON.stringify({
8
+ Name: name,
9
+ TTL: `${ttl}s`,
10
+ Behavior: "delete",
11
+ }),
12
+ });
13
+
14
+ if (res.ok) {
15
+ const { ID: id } = await res.json();
16
+
17
+ return id;
18
+ } else {
19
+ console.log(res, await res.text());
20
+
21
+ return null;
22
+ }
23
+ } catch (fetchErr) {
24
+ console.log("error fetching", fetchErr);
25
+
26
+ return null;
27
+ }
28
+ }
29
+
30
+ async function renewLock(uid) {
31
+ try {
32
+ const res = await fetch(`http://localhost:8500/v1/session/renew/${uid}`, {
33
+ method: "PUT",
34
+ });
35
+
36
+ if (res.ok) {
37
+ return uid;
38
+ } else {
39
+ console.log(res, await res.text());
40
+
41
+ return null;
42
+ }
43
+ } catch (fetchErr) {
44
+ console.log("error fetching", fetchErr);
45
+
46
+ return null;
47
+ }
48
+ }
49
+
50
+ async function hasLock(name, uid = null) {
51
+ try {
52
+ const res = await fetch(`http://localhost:8500/v1/session/list`);
53
+
54
+ if (res.ok) {
55
+ const sessions = await res.json();
56
+
57
+ const sessionsWithTheSameName = sessions.filter((s) => s.Name === name);
58
+
59
+ if (!uid) {
60
+ return sessionsWithTheSameName.length === 0;
61
+ }
62
+
63
+ if (sessionsWithTheSameName.length !== 1) {
64
+ return false;
65
+ }
66
+
67
+ // only one should have the same uid
68
+ return sessionsWithTheSameName[0].ID === uid;
69
+ } else {
70
+ console.log(await res.text());
71
+
72
+ return true;
73
+ }
74
+ } catch (fetchErr) {
75
+ console.log("error fetching", fetchErr);
76
+
77
+ return true;
78
+ }
79
+ }
80
+
81
+ async function useLock({ name, ttl, verbose }) {
82
+ const lockWarningMessage = `only one process with the same lock name ${name} should be running, terminate current process`;
83
+
84
+ const lockAvailable = await hasLock(name);
85
+
86
+ if (!lockAvailable) {
87
+ console.log(lockWarningMessage);
88
+ process.exit(0);
89
+ }
90
+
91
+ let uid = await acquireLock(name, ttl);
92
+
93
+ setInterval(async () => {
94
+ if (!(await hasLock(name, uid))) {
95
+ console.log(lockWarningMessage);
96
+ process.exit(0);
97
+ }
98
+
99
+ if (uid) {
100
+ if (verbose) {
101
+ console.log("renewing", name, uid);
102
+ }
103
+
104
+ uid = await renewLock(uid);
105
+ } else {
106
+ uid = await acquireLock(name, ttl);
107
+ }
108
+ }, (ttl * 1000) / 2);
109
+
110
+ return uid;
111
+ }
112
+
113
+ module.exports = { useLock };
package/examples/api CHANGED
File without changes
package/examples/consumer CHANGED
File without changes
package/examples/indexer CHANGED
File without changes
File without changes
package/examples/producer CHANGED
File without changes
package/kafka.js CHANGED
@@ -2,9 +2,10 @@ const meow = require("meow");
2
2
  const { getEnvironment, getEnvOrThrow } = require("./env");
3
3
  const { wait } = require("./availability");
4
4
  const { Kafka, logLevel } = require("kafkajs");
5
- const { getSelectorFlags, getSelectorDesc, toSelectorString } = require("./selector");
5
+ const { getJobName, getSelectorFlags, getSelectorDesc, toSelectorString } = require("./selector");
6
6
  const { createRecord, getRecordByKey, deleteRecordsByHashKey } = require("./dynamodb");
7
7
  const { exponentialRetry } = require("./availability");
8
+ const { useLock } = require("./distributed-lock");
8
9
  const { getBinaryName } = require("./cli");
9
10
  const { inline } = require("./log");
10
11
 
@@ -218,6 +219,8 @@ ${getSelectorDesc(selector)}
218
219
  process.exit(0);
219
220
  }
220
221
 
222
+ await useLock({ name: getJobName(name, selectorFlags), ttl: 120, verbose });
223
+
221
224
  if (!from) {
222
225
  const prevId = await getProducerLatestId(name, selectorFlags);
223
226
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@certik/skynet",
3
- "version": "0.10.10",
3
+ "version": "0.10.13",
4
4
  "description": "Skynet Shared JS library",
5
5
  "main": "index.js",
6
6
  "author": "CertiK Engineering",
package/selector.js CHANGED
@@ -46,7 +46,32 @@ function toSelectorString(selectorFlags, delim = ",") {
46
46
  .join(delim);
47
47
  }
48
48
 
49
+ function normalizeSelectorValue(v) {
50
+ return v.replace(/[^A-Za-z0-9]+/g, "-");
51
+ }
52
+
53
+ function getJobName(name, selectorFlags, mode = null) {
54
+ const selectorNamePart = Object.keys(selectorFlags)
55
+ .sort()
56
+ .map((name) => selectorFlags[name])
57
+ .join("-");
58
+
59
+ let jobName = name;
60
+
61
+ if (mode) {
62
+ jobName += `-${mode}`;
63
+ }
64
+
65
+ if (selectorNamePart.length > 0) {
66
+ // handle special case
67
+ jobName += `-${normalizeSelectorValue(selectorNamePart)}`;
68
+ }
69
+
70
+ return jobName;
71
+ }
72
+
49
73
  module.exports = {
74
+ getJobName,
50
75
  getSelectorDesc,
51
76
  getSelectorFlags,
52
77
  toSelectorString,