With Neo4j & RabbitMQ

Vinodh Subramanian
Mar 31 · 5 min read
Go — Neo4j — RabbitMQ

What is Eventing?

“Eventing is just notifying someone about something that happened which they are interested in” — too simple isn’t it. The kind of eventing which we are talking about is an asynchronous integration pattern for microservices. To be specific, it’s called the Data Event Exchange.

This is a scenario where one or more microservices subscribe to data change events (change data capture - CDC) directly from a NoSQL store and notified upon data changes.

Any interaction with the store which triggered a data change, like data being persisted, existing data being modified or deleted, will be notified. Events which are generated contain most preferably the updated data itself.

What is a Trigger?

Triggers can be considered a mechanism who does some action based on an event.

So in a database, there are triggers which do the same as stated before. You can enable them to make database do something other than just accepting data changes passively. As are talking about eventing, we can make the database react to events as well.

Enough of theories. Now let’s get to actual work.

Our use case is, we’ll create a node called DB along with few properties of it, in Neo4j.

// cypher query which creates the DB node with its propertiesCREATE (a:DB) SET a.id = 0, a.name = "Redis", a.type = "Cache" RETURN a.id

A Go application which will receive the data change event from RabbitMQ triggered by Neo4j.

//Event received from RabbitMQ by Go applicationReceived an event: {"Labels":["DB"],"Properties":{"name":"Redis","id":"0","type":"Cache"}}

Following is the steps to achieve this.

  1. Go application which creates data in Neo4j
  2. On node creation, Neo4j will trigger an event to RabbitMQ
  3. Go application, again, which will consume the same events from RabbitMQ.

Go application to create a node in Neo4j

We have already done this in my previous post. If you’ve not read it please take a look into it. I’ve modified the code a bit. Just the cypher query which creates the node.

Go method to execute a create node event

The complete source code is available at createnode.go


Neo4j to trigger event to RabbitMQ

Here comes the interesting part. How does trigger work?

Triggers require two pieces of information:

  • Condition (which event should the trigger fire on?)
  • Action (what to do when the trigger fires?)

Triggers are enabled in Neo4j through APOC(Awesome Procedures on Cypher), a clear and well-documented extension library.

Go ahead and install the plugin to your graph as documented in the readme. And add the following configuration to neo4j.conf file.

apoc.trigger.enabled=true

This will enable the trigger mechanism. Let’s continue with our trigger.

CALL apoc.trigger.add('createEvent',   
"UNWIND apoc.trigger.nodesByLabel({assignedLabels}, 'DB') AS node
CALL rabbitmq.event(labels(node), node) return count(*)",
{ phase: 'after' });
// Trigger to be executed in our Neo4j Graph

Wait a minute… What is this now?
This is how we write an apoc trigger. Let’s break this out.

The first argument ‘createEvent’ is the name of the trigger. Which can be later used to check the status of the trigger or to disable it completely.

Second is the cypher query which gets executed as part of this trigger.
Let’s break it even further

  1. “apoc.trigger.nodesByLabel({assignedLabels}, ‘DB’)” command let’s you find out all the nodes which got recently created or assigned by the label ‘DB’. Since it returns a list of nodes we use “UNWIND” to iterate through them, to execute the proceeding cypher statement, with a variable name “node”.
  2. “CALL rabbitmq.event(labels(node), node) return count(*)”, a procedure call made to send out event information about the node which got created.
  3. The cypher statement returns the count of ‘DB’ nodes which got created and passed on.

As per the date when this blog is written, Neo4j doesn’t support streaming data to RabbitMQ by default. For Kafka users, Neo4j has recently launched support for streaming events.

Whereas for RabbitMQ folks, we should be hanging for bit more until there is support from Neo4j officially. But that doesn’t stop us from building what we want?
We can achieve this feature via User Defined Procedures. For today’s task, I’ve quickly written some code to create a procedure which will receive the node details, labels and properties, and event it out to RabbitMQ Queue. Following two code snippets shows how it is done. They are self-explanatory.

Neo4j user-defined procedure to receive node label and property details.
Simple RabbitMQ connection. It’s not optimised for production deployment.

Clone/Download the source code. Change the configuration of RabbitMQ if needed and build a jar. Place it in the Neo4j Plugin folder and restart your graph. That makes the procedure available to your Neo4j instance.

The final argument “{ phase: ‘after’ }” of the trigger allows you to control when your trigger action fires. We can choose from 3 possible lifecycles of transactions, — “before”, “after”, or “rollback”. Since we want our event to be triggered once the node got persisted, we use “after”.

Okay, go ahead and execute the apoc.trigger.add command in your Neo4j graph.


Go application to receive the RabbitMQ events

This one is straight forward. I’ve used the HelloWorld tutorial by RabbitMQ for GoLang to do this. Made a bit of tweak to the code, queue name and queue declaration properties.

Establishing a RabbitMQ connection in go application.

The complete source code is available at receivecreateevents.go


Let’s see them at work

Make sure the Neo4j application and RabbitMQ service are up and running as per your configuration.
Run the go application in two different terminals

go run createnode.go
go run receivecreateevents.go

If everything went well. You should get

In createnode.go terminal
-------------------------
Eventing Graph Data - Neo4j & RabbitMQ
Node Created With ID : 0
In receivecreateevents.go terminal
----------------------------------
[*] Waiting for events. To exit press CTRL+C
Received an event: {"Labels":["DB"],"Properties":{"name":"Reddis","id":"0","type":"Cache"}}

So that’s it for this post. Feel free to comment on the content.

Neo4j Developer Blog

Developer Content around Graph Databases, Neo4j, Cypher, Data Science, Graph Analytics, GraphQL and more.

Vinodh Subramanian

Written by

Software engineer @ Dell Technologies and a Tech enthusiast. Working with Neo4j, RabbitMQ, Golang, Spring boot...

Neo4j Developer Blog

Developer Content around Graph Databases, Neo4j, Cypher, Data Science, Graph Analytics, GraphQL and more.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade