GithubHelp home page GithubHelp logo

flitbit / fiver Goto Github PK

View Code? Open in Web Editor NEW
1.0 2.0 0.0 710 KB

An undersized, opinionated, RabbitMQ library for common messaging patterns in Nodejs.

License: MIT License

TypeScript 96.42% JavaScript 3.58%

fiver's Introduction

fiver · CircleCI npm PRs Welcome GitHub license

A runt of a RabbitMQ client

fiver is a small, opinionated, RabbitMQ client for Nodejs that overlays my preferred AMQP patterns on the ubiquitous amqplib.

I hope you find it useful.

Installing / Getting started

fiver is installed using npm:

npm install -S fiver

In the above command we install fiver into the local project, updating the dependencies in the project.json file.

Use

Broker

RabbitMQ itself if a message broker, therefore, our main class is a Broker. Brokers are intended to live the life of your application.

import { Broker } from 'fiver';
export const broker = new Broker(process.env.AMQP_URI);

In the above commands, we import the Broker class and instantiate an instance using a URI provided in an environment variable.

Publisher

Many applications need to publish messages; we have a Publisher class for that.

import { Broker } from 'fiver';
export const broker = new Broker(process.env.AMQP_URI);
export const publisher = broker.createPublisher();

publisher.publish('daqueue', 'Hello World!')
  .catch(err => console.log(`Oops!: ${err}`));

In the above command we create a publisher and send a message to a queue.

We recommend that you create a dedicated publisher for your application instead of using the broker's publish convenience method.

import { Broker } from '../dist'; // 'fiver';
import { delay, awaitShutdown, blockUntilCount } from './util';
import { EOL } from 'os';

// You need an instance of RabbitMQ running somewhere, look at this project's
// docker-compose.yml if you want to run one locally for testing.
const uri = process.env.AMQP_URI || 'amqp://guest:guest@localhost:5672/';

const transient = {
  durable: false,
  autoDelete: true,
};

const exchange = 'tasks';
const message = 'Work task';

let count = 0;

const sender = async (): Promise<void> => {
  const broker = new Broker(uri);
  try {
    await broker.assertExchange(exchange, 'fanout', transient);

    // write tasks in the background until shutdown
    const shuttingDown: boolean[] = [];
    Promise.resolve()
      .then(async () => {
        const publisher = broker.createPublisher({ publisherConfirms: true, autoConfirm: true });
        try {
          while (shuttingDown.length == 0) {
            await publisher.publish(`${exchange}:`, `${message} ${++count}`);
            process.stdout.write(`\rtask ${count}`);
            // simulate other work with a random wait...
            await delay(Math.floor(Math.random() * Math.floor(500)));
          }
        } finally {
          await publisher.close();
        }
        console.log(EOL + 'done');
      })
      .then(() => shuttingDown.push(true));

    console.log('Sending tasks, press CTRL+C to exit...');
    await awaitShutdown();
    shuttingDown.push(true);
    blockUntilCount(2, () => shuttingDown.length);
  } finally {
    await broker.close();
  }
};

Promise.resolve()
  .then(sender)
  .catch(e => console.error(`An unexpected error occurred: ${e.stack || e}`));

In the above script [examples/producer.ts], in the background process, we create a separate Publisher class using the Broker's .createPublisher(publisherOptions?) method. Then we repeatedly publish messages until the program is interrupted.

The examples/producer.ts script is intended to be run along side one or more examples/consumer.ts scripts.

If you've cloned this repository you can run the producer with the following commands in a bash shell:

npm install
npm run build
./node_modules/.bin/ts-node examples/publisher.ts

Consumer

Many applications need to consume messages; we have a Consumer or that.

import { Broker, Consumer, Message } from '../dist'; // 'fiver';
import { awaitShutdown, delay } from './util';

// You need an instance of RabbitMQ running somewhere, look at this project's
// docker-compose.yml if you want to run one locally for testing.
const uri = process.env.AMQP_URI || 'amqp://guest:guest@localhost:5672/';

const transient = {
  durable: false,
  autoDelete: true,
};

const exchange = 'tasks';

const receiver = async (): Promise<void> => {
  const broker = new Broker(uri);
  try {
    await broker.assertExchange(exchange, 'fanout', transient);
    const q = await broker.assertQueue('', Object.assign({ exclusive: true }, transient));

    await broker.bindQueue(q.queue, exchange, '');
    await broker.prefetch(1);

    const consumer = new Consumer(broker);
    try {
      consumer.on(
        'message',
        async (m: Message): Promise<void> => {
          console.log(`message: ${m.content}`);
          // simulate that the business logic takes time.
          await delay(Math.floor(Math.random() * Math.floor(1000)));
          m.ack();
        }
      );

      consumer.consume(q.queue, { noAck: false });

      console.log('Receiving tasks, press CTRL+C to exit...');
      await awaitShutdown();
    } finally {
      await consumer.close();
    }
  } finally {
    await broker.close();
  }
};

Promise.resolve()
  .then(receiver)
  .catch(e => console.error(`An unexpected error occurred: ${e.stack || e}`));

In the above script [examples/consumer.ts], we create a separate Consumer and subscribe to the 'message' event. When messages arrive we print them on the console, then simulate some work with a random delay before acknowledging the message.

The examples/consumer.ts script is intended to be run along side the examples/publisher.ts script.

If you've cloned this repository you can run the consumer with following commands in a bash shell:

npm install
npm run build
./node_modules/.bin/ts-node examples/consumer.ts

Message

Messages are the whole point of AMQP and Rabbit MQ. fiver wraps all incoming messages in a convenient Message class enabling messages to be handed off to message handlers that aren't coupled with the rest of the AMQP plumbing.

  • .ack(allUpTo?) · acknowledges the message
  • .nack(allUpTo?, requeue?) · nacks the message (negative acknowledgement)
  • .reject(requeue?) · rejects the message

Tests

Tests are built using Mocha and require a RabbitMQ connection string. If you've got docker-compose installed (and port 5672 available) you can follow these commands to run the tests:

npm run devup
npm test

In the above command, the npm run devup script uses docker-compose to stand up an instance of RabbitMQ in a docker container bound to your local port 5672. This enables the npm test script to run using the test's defaults.

If you have an instance of RabbitMQ running somewhere else, set an AMQP_URI environment variable indicating where it is:

AMQP_URI=amqp://guest:[email protected]:5672/test npm test

In the above command we're setting the AMQP_URI environment variable for our tests.

Licensing

This project is licensed by the MIT license found in this repository's root.

fiver's People

Contributors

dependabot[bot] avatar

Stargazers

Shay Zalman avatar

Watchers

James Cloos avatar  avatar

fiver's Issues

src/consumer-middleware.ts throws error about charset not assignable to parameter of type 'BufferEncoding'

Building (yarn build or tsc) at the top level, produces the following error.

src/consumer-middleware.ts:47:53 - error TS2345: Argument of type 'string' is not assignable to parameter of type 'BufferEncoding'.

47         return msg.overrideContent(content.toString(charset));
                                                       ~~~~~~~

src/consumer-middleware.ts:65:51 - error TS2345: Argument of type 'string' is not assignable to parameter of type 'BufferEncoding'.

65           const obj = JSON.parse(content.toString(charset));
                                                     ~~~~~~~

Casting the charset like so,

    return msg.overrideContent(content.toString(charset as BufferEncoding));

Makes the build succeed and run, but the worker.ts message output comes through as a byte array versus the JSON of which message was thought to handle. Thoughts, advice, workarounds, pretty please?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.