Payload Context

Sometimes it is beneficial to pass some contextual information from the trigger to the trigger listener along the payload. Examples are:

  • tracing information that allows to track complex request processing in a multi component system

  • in a multitenant system a tenant information to be able to identify the tenant that peformed an operation that triggered a notification

This can be done by using Payload Context. This feature includes:

  • ability to add an additional information to the payload in the trigger

  • ability to filter by the fields in the context in the listener process

  • ability to use context fields in the listener callbacks

Add context to payload in the trigger

Before doing updates that produce notifications set the context that should be passed using pgpubsub.set_notification_context function.

from pgpubsub import set_notification_context

set_notification_context({'some-key': 'some-value'})

The setting is effective till the connection is closed. Alternatively the setting PGPUBSUB_TX_BOUND_NOTIFICATION_CONTEXT=True can be used to clean the context at the end of the current transanction.

Filter by context field in the trigger listener

Note: that the filtering is currently supported only for stored notifications that is only for channels with lock_notifications = True.

Define a class that implements the ListenerFilterProvider protocol and set the option PGPUBSUB_LISTENER_FILTER to its fully qualified class name.

from pgpubsub import ListenerFilterProvider

class TenantListenerFilterProvider(ListenerFilterProvider):
    def get_filter(self) -> Q:
        return Q(payload__context__tenant='my-tenant')

# django settings
PGPUBSUB_LISTENER_FILTER = 'myapp.whatever.TenantListenerFilterProvider'

This configuration will skip any notifications that do not have tenant field equal to my-tenant in the payload’s context field.

Pass context field to the trigger listener callback

To enable this set PGPUBSUB_CONTEXT_TO_LISTENERS to True in django settings and add a context parameter to the listener callback.

# listeners.py
import pgpubsub
from pgpubsub.tests.channels import AuthorTriggerChannel
from pgpubsub.tests.models import Author, Post

@pgpubsub.post_insert_listener(AuthorTriggerChannel)
def create_first_post_for_author(
    old: Author, new: Author, context: Dict[str, Any]
):
    print(f'Creating first post for {new.name} with context={context}')
    Post.objects.create(
        author_id=new.pk,
        content='Welcome! This is your first post',
        date=datetime.date.today(),
    )

# django settings
PGPUBSUB_PASS_CONTEXT_TO_LISTENERS = True