RedisPubSubTrigger for Azure Functions

Redis features publish/subscribe functionality that enables messages to be sent to Redis and broadcast to subscribers.

For more information about Azure Cache for Redis triggers and bindings, Redis Extension for Azure Functions.

Scope of availability for functions triggers

Tier Basic Standard, Premium Enterprise, Enterprise Flash
Pub/Sub Trigger Yes Yes Yes

Warning

This trigger isn't supported on a consumption plan because Redis PubSub requires clients to always be actively listening to receive all messages. For consumption plans, your function might miss certain messages published to the channel.

Important

The Node.js v4 model for Functions isn't yet supported by the Azure Cache for Redis extension. For more details about how the v4 model works, refer to the Azure Functions Node.js developer guide. To learn more about the differences between v3 and v4, refer to the migration guide.

Important

The Python v2 model for Functions isn't yet supported by the Azure Cache for Redis extension. For more details about how the v2 model works, refer to the Azure Functions Python developer guide.

Examples

Execution mode Description
In-process Your function code runs in the same process as the Functions host process. Supports only Long Term Support (LTS) versions of .NET. To learn more, see Develop .NET class library functions.
Isolated worker process Your function code runs in a separate .NET worker process. Use with supported versions of .NET and .NET Framework. To learn more, see Develop .NET isolated worker process functions.

Important

For .NET functions, using the isolated worker model is recommended over the in-process model. For a comparison of the in-process and isolated worker models, see differences between the isolated worker model and the in-process model for .NET on Azure Functions.

This sample listens to the channel pubsubTest.

using Microsoft.Extensions.Logging;

namespace Microsoft.Azure.Functions.Worker.Extensions.Redis.Samples.RedisPubSubTrigger
{
    internal class SimplePubSubTrigger
    {
        private readonly ILogger<SimplePubSubTrigger> logger;

        public SimplePubSubTrigger(ILogger<SimplePubSubTrigger> logger)
        {
            this.logger = logger;
        }

        [Function(nameof(SimplePubSubTrigger))]
        public void Run(
            [RedisPubSubTrigger(Common.connectionStringSetting, "pubsubTest")] string message)
        {
            logger.LogInformation(message);
        }
    }
}

This sample listens to any keyspace notifications for the key keyspaceTest.

using Microsoft.Extensions.Logging;

namespace Microsoft.Azure.Functions.Worker.Extensions.Redis.Samples.RedisPubSubTrigger
{
    internal class KeyspaceTrigger
    {
        private readonly ILogger<KeyspaceTrigger> logger;

        public KeyspaceTrigger(ILogger<KeyspaceTrigger> logger)
        {
            this.logger = logger;
        }

        [Function(nameof(KeyspaceTrigger))]
        public void Run(
            [RedisPubSubTrigger(Common.connectionStringSetting, "__keyspace@0__:keyspaceTest")] string message)
        {
            logger.LogInformation(message);
        }
    }
}

This sample listens to any keyevent notifications for the delete command DEL.

using Microsoft.Extensions.Logging;

namespace Microsoft.Azure.Functions.Worker.Extensions.Redis.Samples.RedisPubSubTrigger
{
    internal class KeyeventTrigger
    {
        private readonly ILogger<KeyeventTrigger> logger;

        public KeyeventTrigger(ILogger<KeyeventTrigger> logger)
        {
            this.logger = logger;
        }

        [Function(nameof(KeyeventTrigger))]
        public void Run(
            [RedisPubSubTrigger(Common.connectionStringSetting, "__keyevent@0__:del")] string message)
        {
            logger.LogInformation($"Key '{message}' deleted.");
        }
    }
}

This sample listens to the channel pubsubTest.

package com.function.RedisPubSubTrigger;

import com.microsoft.azure.functions.*;
import com.microsoft.azure.functions.annotation.*;
import com.microsoft.azure.functions.redis.annotation.*;

public class SimplePubSubTrigger {
    @FunctionName("SimplePubSubTrigger")
    public void run(
            @RedisPubSubTrigger(
                name = "req",
                connection = "redisConnectionString",
                channel = "pubsubTest",
                pattern = false)
                String message,
            final ExecutionContext context) {
            context.getLogger().info(message);
    }
}


This sample listens to any keyspace notifications for the key myKey.

package com.function.RedisPubSubTrigger;

import com.microsoft.azure.functions.*;
import com.microsoft.azure.functions.annotation.*;
import com.microsoft.azure.functions.redis.annotation.*;

public class KeyspaceTrigger {
    @FunctionName("KeyspaceTrigger")
    public void run(
            @RedisPubSubTrigger(
                name = "req",
                connection = "redisConnectionString",
                channel = "__keyspace@0__:keyspaceTest",
                pattern = false)
                String message,
            final ExecutionContext context) {
            context.getLogger().info(message);
    }
}

This sample listens to any keyevent notifications for the delete command DEL.

package com.function.RedisPubSubTrigger;

import com.microsoft.azure.functions.*;
import com.microsoft.azure.functions.annotation.*;
import com.microsoft.azure.functions.redis.annotation.*;

public class KeyeventTrigger {
    @FunctionName("KeyeventTrigger")
    public void run(
            @RedisPubSubTrigger(
                name = "req",
                connection = "redisConnectionString",
                channel = "__keyevent@0__:del",
                pattern = false)
                String message,
            final ExecutionContext context) {
            context.getLogger().info(message);
    }
}

This sample uses the same index.js file, with binding data in the function.json file determining on which channel the trigger occurs.

Here's the index.js file:

module.exports = async function (context, message) {
    context.log(message);
}

From function.json:

Here's binding data to listen to the channel pubsubTest.

{
  "bindings": [
    {
      "type": "redisPubSubTrigger",
      "connection": "redisConnectionString",
      "channel": "pubsubTest",
      "pattern": false,
      "name": "message",
      "direction": "in"
    }
  ],
  "scriptFile": "index.js"
}

Here's binding data to listen to keyspace notifications for the key keyspaceTest.

{
  "bindings": [
    {
      "type": "redisPubSubTrigger",
      "connection": "redisConnectionString",
      "channel": "__keyspace@0__:keyspaceTest",
      "pattern": false,
      "name": "message",
      "direction": "in"
    }
  ],
  "scriptFile": "index.js"
}

Here's binding data to listen to keyevent notifications for the delete command DEL.

{
  "bindings": [
    {
      "type": "redisPubSubTrigger",
      "connection": "redisConnectionString",
      "channel": "__keyevent@0__:del",
      "pattern": false,
      "name": "message",
      "direction": "in"
    }
  ],
  "scriptFile": "index.js"
}

This sample uses the same run.ps1 file, with binding data in the function.json file determining on which channel the trigger occurs.

Here's the run.ps1 file:

param($message, $TriggerMetadata)
Write-Host $message

From function.json:

Here's binding data to listen to the channel pubsubTest.

{
  "bindings": [
    {
      "type": "redisPubSubTrigger",
      "connection": "redisConnectionString",
      "channel": "pubsubTest",
      "pattern": false,
      "name": "message",
      "direction": "in"
    }
  ],
  "scriptFile": "run.ps1"
}

Here's binding data to listen to keyspace notifications for the key keyspaceTest.

{
  "bindings": [
    {
      "type": "redisPubSubTrigger",
      "connection": "redisConnectionString",
      "channel": "__keyspace@0__:keyspaceTest",
      "pattern": false,
      "name": "message",
      "direction": "in"
    }
  ],
  "scriptFile": "run.ps1"
}

Here's binding data to listen to keyevent notifications for the delete command DEL.

{
  "bindings": [
    {
      "type": "redisPubSubTrigger",
      "connection": "redisConnectionString",
      "channel": "__keyevent@0__:del",
      "pattern": false,
      "name": "message",
      "direction": "in"
    }
  ],
  "scriptFile": "run.ps1"
}

The Python v1 programming model requires you to define bindings in a separate function.json file in the function folder. For more information, see the Python developer guide.

This sample uses the same __init__.py file, with binding data in the function.json file determining on which channel the trigger occurs.

Here's the __init__.py file:

import logging

def main(message: str):
    logging.info(message)

From function.json:

Here's binding data to listen to the channel pubsubTest.

{
  "bindings": [
    {
      "type": "redisPubSubTrigger",
      "connection": "redisConnectionString",
      "channel": "pubsubTest",
      "pattern": false,
      "name": "message",
      "direction": "in"
    }
  ],
  "scriptFile": "__init__.py"
}

Here's binding data to listen to keyspace notifications for the key keyspaceTest.

{
  "bindings": [
    {
      "type": "redisPubSubTrigger",
      "connection": "redisConnectionString",
      "channel": "__keyspace@0__:keyspaceTest",
      "pattern": false,
      "name": "message",
      "direction": "in"
    }
  ],
  "scriptFile": "__init__.py"
}

Here's binding data to listen to keyevent notifications for the delete command DEL.

{
  "bindings": [
    {
      "type": "redisPubSubTrigger",
      "connection": "redisConnectionString",
      "channel": "__keyevent@0__:del",
      "pattern": false,
      "name": "message",
      "direction": "in"
    }
  ],
  "scriptFile": "__init__.py"
}

Attributes

Parameter Description Required Default
Connection The name of the application setting that contains the cache connection string, such as: <cacheName>.redis.cache.chinacloudapi.cn:6380,password... Yes
Channel The pub sub channel that the trigger should listen to. Supports glob-style channel patterns. This field can be resolved using INameResolver. Yes

Annotations

Parameter Description Required Default
name Name of the variable holding the value returned by the function. Yes
connection The name of the application setting that contains the cache connection string, such as: <cacheName>.redis.cache.chinacloudapi.cn:6380,password... Yes
channel The pub sub channel that the trigger should listen to. Supports glob-style channel patterns. Yes

Configuration

function.json property Description Required Default
type Trigger type. For the pub sub trigger, the type is redisPubSubTrigger. Yes
connection The name of the application setting that contains the cache connection string, such as: <cacheName>.redis.cache.chinacloudapi.cn:6380,password... Yes
channel Name of the pub sub channel that is being subscribed to. Yes
pattern A boolean to indicate the given channel uses pattern mathching. If pattern is true, then the channel is treated like a glob-style pattern instead of as a literal. Yes
name Name of the variable holding the value returned by the function. Yes
direction Must be set to in. Yes

Important

The connection parameter does not hold the Redis cache connection string itself. Instead, it points to the name of the environment variable that holds the connection string. This makes the application more secure. For more information, see Redis connection string.

Usage

Redis features publish/subscribe functionality that enables messages to be sent to Redis and broadcast to subscribers. The RedisPubSubTrigger enables Azure Functions to be triggered on pub/sub activity. The RedisPubSubTriggersubscribes to a specific channel pattern using PSUBSCRIBE, and surfaces messages received on those channels to the function.

Prerequisites and limitations

  • The RedisPubSubTrigger isn't capable of listening to keyspace notifications on clustered caches.
  • Basic tier functions don't support triggering on keyspace or keyevent notifications through the RedisPubSubTrigger.
  • The RedisPubSubTrigger isn't supported on a consumption plan because Redis PubSub requires clients to always be actively listening to receive all messages. For consumption plans, your function might miss certain messages published to the channel.
  • Functions with the RedisPubSubTrigger shouldn't be scaled out to multiple instances. Each instance listens and processes each pub sub message, resulting in duplicate processing.

Warning

This trigger isn't supported on a consumption plan because Redis PubSub requires clients to always be actively listening to receive all messages. For consumption plans, your function might miss certain messages published to the channel.

Triggering on keyspace notifications

Redis offers a built-in concept called keyspace notifications. When enabled, this feature publishes notifications of a wide range of cache actions to a dedicated pub/sub channel. Supported actions include actions that affect specific keys, called keyspace notifications, and specific commands, called keyevent notifications. A huge range of Redis actions are supported, such as SET, DEL, and EXPIRE. The full list can be found in the keyspace notification documentation.

The keyspace and keyevent notifications are published with the following syntax:

PUBLISH __keyspace@0__:<affectedKey> <command>
PUBLISH __keyevent@0__:<affectedCommand> <key>

Because these events are published on pub/sub channels, the RedisPubSubTrigger is able to pick them up. See the RedisPubSubTrigger section for more examples.

Important

In Azure Cache for Redis, keyspace events must be enabled before notifications are published. For more information, see Advanced Settings.

Type Description
string The channel message serialized as JSON (UTF-8 encoded for byte types) in the format that follows.
Custom The trigger uses Json.NET serialization to map the message from the channel into the given custom type.

JSON string format

{
  "SubscriptionChannel":"__keyspace@0__:*",
  "Channel":"__keyspace@0__:mykey",
  "Message":"set"
}

Type Description
string The channel message serialized as JSON (UTF-8 encoded for byte types) in the format that follows.
Custom The trigger uses Json.NET serialization to map the message from the channel from a string into a custom type.
{
  "SubscriptionChannel":"__keyspace@0__:*",
  "Channel":"__keyspace@0__:mykey",
  "Message":"set"
}