Typescript 单例未定义属性

Typescript Singleton Undefined Attribute

我正在尝试创建一个具有单个 amqp 连接的单例,当调用 createChannel 方法时,它必须 return 来自同一连接的新通道:

export interface IBroker {
  createChannel(): Promise<IChannel>;
}

export default class Broker implements IBroker {
  private static instance: Broker;

  private conn: IConnection | undefined;

  private constructor(public config: IRabbitMQConfig = new RabbitMQConfig()) {}

  /**
   * singleton
   */
  public static getInstance(): Broker {
    if (!this.instance) {
      this.instance = new Broker();
    }
    return this.instance;
  }

  /**
   * initiates configuration on infra service
   */
  async createChannel(): Promise<IChannel> {
    try {
      if (!this.conn) {
        this.conn = await this.config.init();
        await this.createExchanges();
        await this.createQueues();
        await this.createBinds();
        logger.info('Broker started successfully');
      }
      if (!this.conn) {
        throw new InternalError('Error starting broker. Missing connection!');
      }
      return await this.conn.createChannel();
    } catch (err) {
      logger.error('Error trying to start broker', err);
      throw new InternalError('Error trying to start broker', 500);
    }
  }

// code...

调用 config.init() returnamqp 连接。

当我像下面这样测试 class 时,每次我调用 createChannel 它都会创建一个新连接!

    const a = Broker.getInstance();
    const b = Broker.getInstance();
    console.log(a === b); // return true
    a.createChannel(); // create a new connection
    b.createChannel(); // creates another connection

Broker class 的

this.conn 在调用 createChannel 时始终未定义!

我认为问题是对 createChannel 的两次同步调用意味着第一个在调用第二个时尚未初始化连接,这导致创建了 2 个连接。

如果您想在创建连接方面使 createChannel“线程安全”,您可以这样做(未经测试):

interface IConnection {
    connect: () => void
}

const initConnection = () : Promise<IConnection> => {
    return Promise.resolve({
        connect: () => {}
    });
};

class Broker {
    private connection : IConnection | undefined;
    private pendingConnection : Promise<IConnection> | undefined;

    async createChannel() : Promise<IConnection> {
        if (this.connection) {
            return this.connection;
        }

        if (this.pendingConnection) {
            return this.pendingConnection;
        }

        this.pendingConnection = initConnection();
        const conn = await this.pendingConnection;
        // Do other setup stuff
        this.connection = conn;
        this.pendingConnection = undefined;
        return conn;
    }
}