Skip to main content

Push Events

Liquid provides a comprehensive push events system that publishes real-time events to either Redis Pub/Sub or RabbitMQ message queues. This allows you to build reactive features and integrate with external services based on user actions and system events.

Overview

When enabled, Liquid publishes events to your configured message queue whenever significant actions occur in the system. These events can be consumed by your applications to trigger notifications, analytics, webhooks, or other reactive behaviors.

Configuration

Enabling Push Events

To enable push events, you need to configure the following options in your app-config.service.json:

{
"privilege.can-use-push-events": true,
"system.queue-adapter": "redis",
"system.push-events": [
"user.follow",
"user.unfollow",
"user.follow-request",
"user.create",
"user.login",
"user.logout",
"user.logout-all",
"email.send"
]
}

Queue Adapters

Liquid supports two message queue adapters:

Redis Pub/Sub

{
"system.queue-adapter": "redis",
"privilege.can-use-cache": true,
"redis.host": "127.0.0.1",
"redis.port": 6379,
"redis.channel-name": "liquid"
}

RabbitMQ

{
"system.queue-adapter": "rabbitmq",
"privilege.can-use-rabbitmq": true,
"rabbitmq.connectionString": "amqp://localhost:5672",
"rabbitmq.channel-name": "liquid"
}

Backend Configuration

Redis Configuration Options

All Redis configuration options for Liquid:

{
"privilege.can-use-cache": true,
"redis.host": "127.0.0.1",
"redis.port": 6379,
"redis.username": "",
"redis.password": "",
"redis.db": 0,
"redis.key-prefix": "",
"redis.channel-name": "liquid"
}

Configuration Details:

OptionTypeDefaultDescription
privilege.can-use-cachebooleantrueEnables Redis caching and pub/sub functionality
redis.hoststring"127.0.0.1"Redis server hostname or IP address
redis.portnumber6379Redis server port number
redis.usernamestring""Redis username (Redis 6.0+)
redis.passwordstring""Redis password for authentication
redis.dbnumber0Redis database number (0-15)
redis.key-prefixstring""Prefix for all Redis keys
redis.channel-namestring"liquid"Channel name for pub/sub events

Redis Security Configuration

For production deployments, configure Redis with authentication:

Redis Configuration (redis.conf):

# Enable authentication
requirepass your-strong-password

# Bind to specific interface (not 0.0.0.0 in production)
bind 127.0.0.1

# Disable dangerous commands
rename-command FLUSHDB ""
rename-command FLUSHALL ""
rename-command CONFIG ""

Liquid Configuration:

{
"redis.host": "your-redis-host",
"redis.port": 6379,
"redis.password": "your-strong-password"
}

RabbitMQ Configuration Options

All RabbitMQ configuration options for Liquid:

{
"privilege.can-use-rabbitmq": true,
"rabbitmq.connectionString": "amqp://username:password@localhost:5672",
"rabbitmq.channel-name": "liquid"
}

Configuration Details:

OptionTypeDefaultDescription
privilege.can-use-rabbitmqbooleanfalseEnables RabbitMQ functionality
rabbitmq.connectionStringstring"amqp://localhost:5672"Full RabbitMQ connection string
rabbitmq.channel-namestring"liquid"Queue name for events

RabbitMQ Connection String Format

The connection string supports various formats:

# Basic connection
amqp://localhost:5672

# With authentication
amqp://username:password@localhost:5672

# With vhost
amqp://username:password@localhost:5672/vhost

# SSL/TLS connection
amqps://username:password@localhost:5671

# With connection parameters
amqp://username:password@localhost:5672?heartbeat=60&connection_timeout=10000

RabbitMQ Security Configuration

For production deployments, configure secure RabbitMQ connections:

Production Configuration:

{
"rabbitmq.connectionString": "amqp://liquid_user:strong_password@rabbitmq-server:5672/liquid_vhost"
}

Event Filtering

You can control which events are published by configuring the system.push-events array. Only events listed in this array will be published to the queue.

Event Prefixing

You can add a prefix to all event names by setting:

{
"system.push-events.prefix": "myapp."
}

This will prefix all events (e.g., user.login becomes myapp.user.login).

Available Events

User Events

user.create

Published when a new user account is created.

Data Structure:

{
"id": "uuid-v4",
"name": "user.create",
"data": {
"user": {
"_id": "user_id",
"username": "john_doe",
"email": "john@example.com",
"firstName": "John",
"lastName": "Doe",
"verified": false,
"role": "user",
"credits": 100,
"scope": ["user:profile:read"],
"createdAt": "2023-01-01T10:00:00.000Z"
}
}
}

user.login

Published when a user successfully logs in (both password and OAuth logins).

Data Structure:

{
"id": "uuid-v4",
"name": "user.login",
"data": {
"user": {
"_id": "user_id",
"username": "john_doe",
"email": "john@example.com",
"firstName": "John",
"lastName": "Doe"
}
}
}

user.logout

Published when a user logs out from a single session.

Data Structure:

{
"id": "uuid-v4",
"name": "user.logout",
"data": {
"user": {
"_id": "user_id",
"username": "john_doe",
"email": "john@example.com",
"firstName": "John",
"lastName": "Doe"
}
}
}

user.logout-all

Published when a user logs out from all sessions.

Data Structure:

{
"id": "uuid-v4",
"name": "user.logout-all",
"data": {
"user": {
"_id": "user_id",
"username": "john_doe",
"email": "john@example.com",
"firstName": "John",
"lastName": "Doe"
}
}
}

Social Events

user.follow

Published when a user successfully follows another user (for public profiles).

Data Structure:

{
"id": "uuid-v4",
"name": "user.follow",
"data": {
"source": "follower_user_id",
"target": "followed_user_id"
}
}

user.follow-request

Published when a user requests to follow a private profile.

Data Structure:

{
"id": "uuid-v4",
"name": "user.follow-request",
"data": {
"source": "requester_user_id",
"target": "target_user_id"
}
}

user.unfollow

Published when a user unfollows another user.

Data Structure:

{
"id": "uuid-v4",
"name": "user.unfollow",
"data": {
"source": "unfollower_user_id",
"target": "unfollowed_user_id"
}
}

Email Events

email.send

Published when an email is sent through the Pusher email adapter. This is useful for implementing custom email sending logic.

Data Structure:

{
"id": "uuid-v4",
"name": "email.send",
"data": {
"email": {
"to": "recipient@example.com",
"from": {
"email": "noreply@yourapp.com",
"name": "Your App"
},
"subject": "Welcome to Your App",
"text": "Plain text content",
"html": "<h1>HTML content</h1>",
"templateId": "template_id",
"dynamicTemplateData": {
"name": "John",
"verification_url": "https://yourapp.com/verify?token=abc123"
},
"timestamp": "2023-01-01T10:00:00.000Z"
}
}
}
info

The email.send event is only published when using the pusher email adapter. Configure this by setting system.email-adapter to "pusher" in your backend configuration.

Event Structure

All events follow a consistent structure:

{
"id": "unique-uuid-v4-identifier",
"name": "event.name",
"data": {
// Event-specific data
}
}
  • id: A unique UUID v4 identifier for each event
  • name: The event name (with optional prefix)
  • data: Event-specific payload containing relevant information

Consuming Events

Redis Pub/Sub Example (Node.js)

const Redis = require("ioredis");
const redis = new Redis({
host: "localhost",
port: 6379,
});

redis.subscribe("liquid");

redis.on("message", (channel, message) => {
const event = JSON.parse(message);

switch (event.name) {
case "user.login":
console.log(`User ${event.data.user.username} logged in`);
break;
case "user.follow":
console.log(`User ${event.data.source} followed ${event.data.target}`);
break;
case "email.send":
// Custom email sending logic
sendCustomEmail(event.data.email);
break;
}
});

RabbitMQ Example (Node.js)

const amqp = require("amqplib");

async function consumeEvents() {
const connection = await amqp.connect("amqp://localhost");
const channel = await connection.createChannel();
const queue = "liquid";

await channel.assertQueue(queue);

channel.consume(queue, (message) => {
if (message) {
const event = JSON.parse(message.content.toString());

switch (event.name) {
case "user.create":
console.log(`New user created: ${event.data.user.username}`);
break;
case "user.logout-all":
console.log(`User ${event.data.user.username} logged out from all sessions`);
break;
}

channel.ack(message);
}
});
}

consumeEvents();

Dependencies

DependencyRequiredUsed For
RedisOptionalRedis Pub/Sub adapter and caching
RabbitMQOptionalRabbitMQ message queue adapter

Redis Dependencies

For Redis Pub/Sub:

  • Ensure privilege.can-use-cache is enabled
  • Redis connection must be properly configured
  • Uses the same Redis instance as Liquid's caching system

RabbitMQ Dependencies

For RabbitMQ:

  • Ensure privilege.can-use-rabbitmq is enabled
  • RabbitMQ connection string must be properly configured
  • Independent message queue system
tip

Events are published asynchronously and won't block the main API response. However, if the message queue is unavailable, events will be silently dropped. Ensure your message queue infrastructure is reliable for production use.

warning

Event payloads may contain sensitive user information. Ensure your message queue and event consumers are properly secured, especially in production environments.