Почему Node не обнаруживает мой недавно созданный файл

У меня есть сценарий Node.js, который подписывается на службу уведомлений и запускает множество вещей при получении push-уведомления. Однако служба иногда отправляет несколько уведомлений для одного и того же события, поэтому, чтобы избежать дублирования работы, я сделал базовый семафор для блокировки других задач.

Проблема в том, что Node все еще продолжает выполнение, несмотря на то, что Я вижу файл, созданный на диске. Я пробовал несколько разных решений, но я думаю, что проблема связана с отсутствием у меня опыта работы с моделью выполнения JS, есть кое-что, чего я не знаю о том, как это работает, что мешает моему решению работать. Как я могу это исправить?

const fse = require('fs-extra');

// notification handler callback
function handleRequest(data)
{
    try{
      var semaphore = fse.readJsonSync(__dirname + '/' + objectId);
      console.info('task already running, stopping');
      return;
    }catch(err){
      // semaphore doesn't exist, ok to proceed
      console.info('starting new task');
      fse.writeJson(__dirname + '/' + objectId, {objectId: objectId})
          .then(stepOne).catch(rejectPromise) 
          .then(resp => stepTwo(resp, data)).catch(rejectPromise)
          .then(resp => stepThree(resp, extra)).catch(rejectPromise)
          .then(resp => stepFour(resp, argument)).catch(rejectPromise)
          .then(sleep(20000))                        
          .then(resp => releaseLock(objectId))
          .catch(resp => rejectionHandler(resp);
    }
}

function releaseLock(objectId)
{
    return fse.remove(__dirname + '/' + objectId);
}

Другие вещи, которые я пробовал

  • Создайте файл в отдельной функции, которая возвращает обещание, тот же результат
  • Используйте метод Sync для записи файла, но тогда я не могу связать обещания
  • Ждать синхронно после создания файла, никакого эффекта

То есть вы говорите, что даже если в блоке try нет ошибки, код попадает в блок catch?

priyansh gupta 03.04.2018 16:53

@priyanshgupta да, это другой взгляд на это. Единственный способ попасть в блок catch - это если файл не существует, но я вижу, что он создан в файловой системе.

blackbird 03.04.2018 16:56
fse.writeJson является асинхронным, поэтому теоретически handleRequest можно было бы вызвать в другой раз до того, как fse.writeJson выполнит какую-либо запись. Вы должны создать монопольную блокировку для objectId, и только если блокировка была создана успешно, вы должны выполнить эту задачу.
t.niese 03.04.2018 16:57

Значит, вам нужно запретить кому-либо вызывать handle request, если вы видите в fs какой-либо файл с тем же objectId?

priyansh gupta 03.04.2018 16:58

@ t.niese, значит, тот факт, что я привязал его через обещание к другим функциям, ничего не меняет? Идея в том, что stepOne не должен запускаться до создания файла.

blackbird 03.04.2018 16:59

@priyanshgupta да именно

blackbird 03.04.2018 16:59
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
1
6
56
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Нет необходимости создавать внешний файл для поддержки блокировок, вы можете сделать что-то вроде этого, это также даст вам повышение производительности (меньше операций ввода-вывода).

const fse = require('fs-extra');

// notification handler callback

class NamedLocks {
    constructor() {
        this._pid = {};
    }

    acquire(pid) {
        if (this._pid[pid]) {
            // process is locked
            // handle it
            return Promise.reject();
        }

        this._pid[pid] = true;
        return Promise.resolve();
    }

    release(pid) {
        delete this._pid[pid];
    }
}

const userLocks = new NamedLocks();


function handleRequest(data) {
    userLocks.acquire(objectId)
        .then(() => {
            // semaphore doesn't exist, ok to proceed
            console.info('starting new task');
            fse.writeJson(__dirname + '/' + objectId, { objectId: objectId })
                .then(stepOne).catch(rejectPromise)
                .then(resp => stepTwo(resp, data)).catch(rejectPromise)
                .then(resp => stepThree(resp, extra)).catch(rejectPromise)
                .then(resp => stepFour(resp, argument)).catch(rejectPromise)
                .then(sleep(20000))
                .then(resp => userLocks.release(objectId))
                .catch(resp => rejectionHandler(resp))
        }).catch(() => {
            // handle lock exist condition here
        });
};

В этом случае вы в основном запрашиваете блокировку, и если блокировка существует, обработайте ее в обработчике catch, иначе сделайте свое дело и освободите блокировку

Да ! великолепно, спасибо вам большое. Я только что проверил это, он отлично работает

blackbird 03.04.2018 17:21

Я бы предпочел использовать release(pid) { delete this._pid[pid]; }, иначе у вас будет небольшая утечка памяти.

Patrick Roberts 03.04.2018 17:25

В качестве примечания: это будет работать нормально, если вы не запустите свое приложение как кластер с несколькими рабочими процессами. Поэтому, если вы планируете использовать больше, чем на ядре процессора в будущем, вы можете добавить проверку в NamedLocks, которая в этом случае вызовет выполнение, которое напоминает вам, что вам нужно реализовать файловую или любую другую глобальную блокировку. @blackbird

t.niese 03.04.2018 17:51

Другие вопросы по теме