Организация очереди SQL-запросов

У меня есть сокет, который прослушивает события (строки) через UDP. Каждый раз, когда он получает строку, генерируется запрос SQL. Моя проблема заключается в том, чтобы он работал асинхронно, чтобы запросы стояли в очереди и не пытались получить доступ к базе данных, пока выполняется другой запрос.

Псевдо:

socket.on('message', function (msg) {
    switch (msg) {
        case "case1":
            storeRows();
            break;
    //there's a new message every 1-2 secs
    ...
}
var rows = []; //push results of all queries here
function storeRows() {
    rows.push(getFromDB());
}

function getFromDB() {
    var sqlString = "SELECT * ..."
    var req = new Req(sqlString, function(err, rowCount) {
...
    }
var resultsArray = [];
req.on('row', function (cols) {
    //add results to resultsArray
}
return resultsArray;
}

В основном мне нужно, чтобы getFromDB () выполнялся асинхронно, дождитесь завершения предыдущего запроса, прежде чем запускать следующий. Я не знаю, как это сделать. Я использую tedious.js для доступа к базе данных SQL Server.

Редактировать:

var config = {
    userName: "admin",
    password: "pw",
    server: "test",
    domain: "test",
    options: {
        port: '10322'
    }
}
connection = new Connection(config);
connection.on('connect') {
    isConnected = true;
}

getCoordinates(vehicleID, fromTime, toTime) { 
    var SQLString = "Select * FROM coordinates WHERE TimeStamp BETWEEN '" + fromTime + "' AND '" + toTime + "' AND vehicleID = " + vehicleID;
    var rowsToSend = [];
    var req = new Req(SQLString, function(err, rowCount) {
        if (err) console.info(err)
        else console.info(rowCount);
    }

    req.on('row', function (columns) {
        var rowArray = [];
        columns.forEach(function (column) {
            var colValue = column.value;
            switch (column.metadata.colName) {
                case "ID":
                    if (rowArray.length > 0)                   
                        rowsToSend.push(rowArray);
                        rowArray = new Array();
                        break;

                default:                     
                    rowArray.push(colValue);
                    break;
                }
         });
         rowsToSend.push(rowArray);
    });
    connection.execSql(req);

    req.on('doneProc', function () {
        return(rowsToSend);
    }  
}

//called every few seconds
function runQueries() {
    someArray.push(getCoordinates ());
}

Из их документация ясно, что запросы к базе данных с использованием tedious.js уже являются асинхронными (как можно было бы надеяться, в среде Node.js). Используете ли вы какую-то опцию или что-то подобное, чтобы вместо этого они блокировались? Не могли бы вы показать нам реальное содержимое getFromDB (с опущенным SQL это нормально)?

T.J. Crowder 13.09.2018 10:14

При отправке запроса во время выполнения другого он возвращает Requests can only be made in the LoggedIn state, not the SentClientRequest state.

user2979612 13.09.2018 10:16

Мы не сможем помочь вам, не увидев больше вашего кода. Но похоже, что проблема не в синхронном и асинхронном, а в каком-то другом виде управления состоянием. Обновите свой вопрос, добавив минимальный воспроизводимый пример, демонстрирующий проблему с простыми запросами (многие из нас имеют доступ к SQL Server и могут быстро настроить локальный пример, чтобы помочь вам).

T.J. Crowder 13.09.2018 10:18

@ T.J.Crowder Какое отношение это имеет к управлению государством? Вопрос кажется довольно простым. У меня есть сообщение, которое должно запрашивать базу данных каждые 1-2 секунды, и я хочу убедиться, что запросы не выполняются параллельно. Ниже я привел пример.

Goodbye StackExchange 13.09.2018 10:28

Обратный вызов, который вы передаете вызову new Req(), должен отвечать на текущее сообщение данными или ошибкой. Затем, если в вашей очереди запросов все еще есть запросы, сделайте то же самое. Таким образом, все запросы, поступающие через сокет, могут оставаться синхронными. Только запрос к базе данных, запускающий сокет для отправки ответа, является асинхронным, поскольку вы хотите дождаться завершения предыдущего запроса, а не выполнять все запросы параллельно. Сохранение ожидающих запросов может быть таким же простым, как нажатие и извлечение массива.

Shilly 13.09.2018 10:30

@FrankerZ - Я не понимаю, как это не может быть связано с управлением состоянием, поскольку OP явно пытается выполнить запрос, когда он не находится в «состоянии LoggedIn». Ответ ниже в лучшем случае является дико спекулятивным.

T.J. Crowder 13.09.2018 10:42

Добавлен пример кода.

user2979612 13.09.2018 10:52

@ user2979612 - Добавленный код содержит основные синтаксические ошибки. Опять же, опубликуйте MCVE.

T.J. Crowder 13.09.2018 11:01

Полный код находится в частной сети, и я не могу легко передать его в Интернет. Это лучшее, что я могу сделать. Но ответ @ FrankerZ - это более или менее то, что я искал.

user2979612 13.09.2018 11:03
Поведение ключевого слова "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) для оценки ваших знаний,...
0
9
1 319
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

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

Вы можете создать что-то вроде процессора, который создает очередь на основе массива и позволяет одновременно выполнять только один запрос к базе данных. Вот пример использования функций async / await с обещаниями:

class Processor {
  constructor() {
    this.queue = [];
    this.queryRunning = false;
  }
  
  // Main query function.
  // Add the query to a queue, and try to process the queue.
  query(query) {
    return new Promise((resolver) => {
      this.queue.push({
        query,
        resolver
      });
      
      this.tryProcessNext();
    });
  }
  
  // Try to process the next element of the queue
  tryProcessNext() {
    let self = this;
    
    // If it's running, or queue is empty, simply do nothing
    if (this.queue.length === 0 || this.queryRunning)
      return;
    
    this.queryRunning = true;
    
    // Get the first added element to the queue (And shorten the array at the same time)
    let qry = this.queue.shift();
    
    // Run query, and use `qry.resolver()` to resolve the original promise.
    setTimeout(function() {
      qry.resolver(`Result: ${qry.query}`);
      self.queryRunning = false;
      // If there's anything next in the queue, try to process that next
      self.tryProcessNext();
    }, 1500);
  }
  
}

const proccessor = new Processor();

let i = 0;
// A simple function to demonstrate adding queries via a websocket.
setInterval(async function() {
  console.info(`Adding query: QUERY ${++i}`);
  var res = await proccessor.query(`QUERY ${i}`);
  
  console.info(res);
}, 1000);

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