каков наилучший способ или шаблон для создания класса-оболочки для абстрагирования использования RabbitMQ в узле js

#node.js #rabbitmq #amqp

#node.js #rabbitmq #amqp

Вопрос:

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

Я начал с создания класса IRAbbitMQ с функцией init для инициализации соединения и создания канала, я знал, что не могу использовать вложенные классы, поэтому вместо этого я хотел использовать заводские функции, я попытался установить соединение и передать часть свойств класса IRabbitMQ, но я не знаю, почему это дало мне undefinedкогда я создаю его экземпляр

 class IRabbitMQ {

constructor() {

    this.init(rabbitMQServer); // rabbitMQServer for example 'localhost//5672'

}
// establish a Connection to RAbbitMQ Server
async init(host) {

    try {

    let connection = await amqplib.connect(host);

    let channel = await connection.createChannel();

    channel.prefetch(1); 

    console.log(' [x] Awaiting RPC requests');

    this.connection = connection;

    this.channel = channel;

    }

    catch(err) {

        console.error(err);
    }

}

// Close the Connection with RabbitMQ
closeConnection() {

    this.connection.close();
}

log() {
    console.log(this.connection);
}

EventPublisher() {

    function init(IRabbit, publisherName) {

        if(!IRabbit.connection) {

            throw new Error('Create an Instance of IRabbitMQ to establish a Connection');

        }

        let ch = IRabbit.channel;
        console.log(ch);
    }
    return {
        init : init
    }   
    }

   }

   var r = new IRabbitMQ();
   r.log();
  

когда я запускаю код, результат не определен, я не знаю почему, поскольку я инициализирую свойства соединения и канала в функции init, а затем вызываю эту функцию в конструкторе, чтобы она инициализировалась при создании объекта класса-оболочки. я также хотел бы получить от вас несколько советов, полезно ли использовать классы или есть какой-либо другой лучший способ создать класс-оболочку или интерфейс для RabbitMQ, чтобы упростить его использование и не дублировать код.

Комментарии:

1. Не могли бы вы уточнить «вывод не определен», что означает, что он где-то регистрирует «undefined»? Мне просто непонятно, где / что происходит сбой 🙂

2. существует функция с именем log(), которая будет console.log(this.connection) , с помощью этой функции я проверил, произошло ли подключение к rabbitmq или нет. Когда я вызываю эту функцию, это консоль. log undefined вместо соединения это означает, что свойство класса connection имеет значение undefined вместо реального соединения, и это меня смущает, потому что, когда я утешаю. регистрируйте свойство connection изнутри функции init, чем оно работает, и регистрирует реальный объект connection. надеюсь, это поможет вам понять вопрос

3. Ну, в этом случае у вас, вероятно, есть условие гонки? Конструктор вызывает init() который является асинхронным. Итак, когда вы создаете экземпляр объекта, а затем вызываете напрямую .log() , есть вероятность, что init() он еще не завершен, поскольку в этот момент он асинхронен. Например, заводская функция была бы лучше const myRabbit = await RabbitMQFactory.create() . Не особенно await перед заводской функцией.

4. он также не работал с заводской функцией: (может быть, вы можете показать мне какой-нибудь код, если он работает с вами, это было бы полезно

Ответ №1:

На самом деле это не ответ, но я смог успешно войти в connection систему с помощью этого примера кода. Я вырезал другой код, чтобы просто сосредоточиться на той .log() части, которая регистрировала a undefined .

Код далек от совершенства, но работает, по крайней мере

 const amqplib = require('amqplib');

class IRabbitMQ {

    constructor() { }

    async init(host) {
        try {
            const connection = await amqplib.connect(host);
            const channel = await connection.createChannel();
            channel.prefetch(1);
            console.log(' [x] Awaiting RPC requests');
            this.connection = connection;
            this.channel = channel;
        }catch(err) {
            console.error(err);
        }
    }

    log() {
        console.log(this.connection);
    }
}

async function createInstance(){
    const instance = new IRabbitMQ();
    try {
        await instance.init('amqp://localhost');
    }catch (e) {
        throw new Error('OOPS!');
    }
    return instance;
}

async function runLogic() {
    const r = await createInstance();
    r.log();
}

runLogic().catch(console.log);
  

Просто прокомментируйте, если вы хотите, чтобы я дал дополнительные советы / подсказки, но, похоже, это работает для меня.

Комментарии:

1. Я очень благодарен вам за усилия, хотя может показаться, что это работает нормально, но, как вы сказали, это немного запутанно, если мой класс будет структурирован таким образом, и, как я написал в описании, моя цель на самом деле состоит в том, чтобы создать оболочку класса для обертывания некоторых функций, чтобы я могмне не нужно все время повторяться и писать какой-то код spaguetti. это работает так, как вы делаете, но моей целью было не регистрировать свойство connection, я хотел, чтобы соединение с rabbitmq было доступно как свойство, чтобы я мог использовать его для других классов или функций.

2. возможно, этот комментарий поможет больше, цель состоит в том, чтобы обернуть все функции публикации и подписки в класс, чтобы в файле publisher мне требовался только этот класс, а затем создать экземпляр и вызвать функции, которые отвечают за публикацию сообщения, и если мне нужно подписаться, я перейду кфайл subscribe и создайте экземпляр этого класса, а затем вызовите функции, ответственные за подписку. этот способ организует мою работу, и если бы у меня была команда, тогда было бы лучше поддерживать код. я надеюсь, что это поможет, и я большое спасибо вам и всем, кто пытается помочь 🙂

3. Я лично не стал бы пытаться принудительно использовать класс. Вам нужно что-то «одноэлементное» на случай, если вы хотите повторно использовать одно и то же соединение (верно?). Если это предположение верно, я бы просто вернул из вашего модуля узла объект с нужными вам методами и сохранил ваше состояние (например, соединение) в виде clojure в вашем файле.

4. в этой ситуации проблема будет заключаться в том, что я не могу назначить соединение свойству класса или вернуть его из функции. например, в функции init, когда я назначаю this.connection = connection и когда я хочу вызвать это свойство connection в другой функции или из экземпляра класса, это соединение будет неопределенным, и я не знаю почему. если я забыл класс и использую только функцию, которая подключается к rabbitmq, а затем возвращает connection, а затем использует его в своем коде для exp let c = establishConnection(); // здесь я получаю также undefined, я не знаю, почему