@igea/oac_backend 1.0.95 → 1.0.96

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": "@igea/oac_backend",
3
- "version": "1.0.95",
3
+ "version": "1.0.96",
4
4
  "description": "Backend service for the OAC project",
5
5
  "main": "src/index.js",
6
6
  "bin": {
@@ -12,6 +12,7 @@ const Fuseki = require('../models/fuseki');
12
12
  const Attachments = require('../models/attachments');
13
13
  const { Parser, transformMode } = require('../models/vocabolaries/parser');
14
14
  const CacheVocabularies = require('../models/vocabolaries/cache');
15
+ const EditLocks = require('../models/editLocks');
15
16
  const VocabParser = Parser.GET_INSTANCE();
16
17
 
17
18
  //---------------------------------------------------------------
@@ -278,8 +279,22 @@ router.get('/get-vocabolary-terms/:key', (req, res) => {
278
279
  }).then(response => {
279
280
  res.setHeader('Content-Type', response.headers['content-type']);
280
281
  res.header('Access-Control-Allow-Origin', '*');
281
- CacheVocabularies.set(key, response.data); // salva come stringa
282
- res.send(response.data);
282
+ const client_uuid = crypto.randomUUID();
283
+ const table = 'vocabulary-cache'
284
+ EditLocks.lockWithRetry(table, key, client_uuid).then( async (success) =>{
285
+ try{
286
+ if(success){
287
+ CacheVocabularies.set(key, response.data); // salva come stringa
288
+ await EditLocks.delete(table, key, client_uuid)
289
+ }
290
+ }catch(ex){
291
+ console.log(ex)
292
+ }
293
+ res.send(response.data);
294
+ }).catch((e)=>{
295
+ console.log(e)
296
+ res.send(response.data);
297
+ })
283
298
  }).catch(err => {
284
299
  res.status(500).json({
285
300
  success: false,
@@ -5,11 +5,49 @@ const expiration_seconds = 180 // 3 minutes
5
5
 
6
6
  class EditLocks {
7
7
 
8
- static lock(table_name, row_id, client_uuid){
8
+ static sleep(delay_ms=100) {
9
+ return new Promise(resolve => setTimeout(resolve, delay_ms));
10
+ }
11
+
12
+ static lockWithRetry(
13
+ table_name,
14
+ row_id,
15
+ client_uuid,
16
+ {
17
+ timeoutMs = 5000, // timeout totale
18
+ expirationMs = 10000, // expiration of the lock
19
+ retryDelayMs = 100 // delay minimo tra i tentativi
20
+ } = {}
21
+ ) {
22
+ return new Promise(async (resolve, reject) => {
23
+ const startTs = (new Date).getTime();
24
+ let continueLocking = true;
25
+ const exp_sec = Math.ceil(expirationMs / 1000)
26
+ while (continueLocking) {
27
+ try {
28
+ console.log("Lock with retry for " + table_name + "@" + row_id)
29
+ const acquired = await EditLocks.lock(table_name, row_id, client_uuid, exp_sec);
30
+ if (acquired === true) {
31
+ resolve(true); // 🔐 lock acquisito
32
+ return;
33
+ }
34
+ } catch (err) {
35
+ console.log(err)
36
+ }
37
+ await EditLocks.sleep(retryDelayMs);
38
+ const curTs = (new Date).getTime();
39
+ continueLocking = (curTs > startTs + timeoutMs)
40
+ }
41
+ // ⛔ timeout raggiunto
42
+ resolve(false)
43
+ })
44
+ }
45
+
46
+ static lock(table_name, row_id, client_uuid, exp_sec = expiration_seconds){
9
47
  return new Promise(async (resolve, reject) => {
10
48
  try{
11
49
  let start_ts = Math.ceil(new Date().getTime()/1000)
12
- let end_ts = start_ts + expiration_seconds
50
+ let end_ts = start_ts + exp_sec
13
51
  let sql = `INSERT INTO ${table}(
14
52
  table_name, row_id, client_uuid,
15
53
  locked_at_ts, expires_at_ts
@@ -63,6 +101,7 @@ class EditLocks {
63
101
 
64
102
  static delete(table_name, row_id, client_uuid){
65
103
  return new Promise(async (resolve, reject) => {
104
+ console.log("Unlock for " + table_name + "@" + row_id)
66
105
  try {
67
106
  await db(table).where(
68
107
  {table_name, row_id, client_uuid}