In neo4j there's the transactional cypher endpoint. This allows the client to spawn a database transaction over multiple REST requests. The first request opens a new transaction and gets back the URL to be used for subsequent requests to the same transaction in a http Location
header containing the transaction id, e.g.
Location: http://192.168.0.10:7474/db/data/transaction/24
The number at the end is the internal transaction id. A subsequent request to close the transaction gets send to http://192.168.0.10:7474/db/data/transaction/24/commit
.
To accomplish that I'm using the following snippet for haproxy's backend configuration:
backend neo4j-all
option httpchk GET /db/manage/server/ha/available
stick-table type integer size 1k expire 10m
stick match path,word(4,/)
stick store-response hdr(Location),word(6,/)
server s1 127.0.0.1:7474 maxconn 32 check
server s2 127.0.0.1:7475 maxconn 32 check
server s3 127.0.0.1:7476 maxconn 32 check
A sticky table gets populated with the transaction id (6th word in location header). The subsequent request's path
contains the transaction id as 4th word. This part works fine.
However I want to limit down the usage of the stick table to paths starting with /db/data/transaction
since Neo4j might have other endpoints as well with different behaviour.
My first naive approach was to simple add an acl
to the backend:
acl tx_cypher_endpoint path_beg /db/data/transaction
and then amend the stick match
and stick store-response
from above with an if tx_cypher_endpoint
. Upon start this causes the following message:
parsing [haproxy.cfg:32] : acl 'tx_cypher_endpoint' will never match because it only involves keywords that are incompatible with 'backend stick-store rule'
Question #1: can someone please explain the reason for this?
As a workaround I've moved the acl to the frontend section and conditionally store a variable with txn
scope that gets used in the backend:
frontend http-in
bind *:8090
acl tx_cypher_endpoint path_beg /db/data/transaction
http-request set-var(txn.tx_cypher_endpoint) bool(true) if tx_cypher_endpoint
default_backend neo4j-all
backend neo4j-all
option httpchk GET /db/manage/server/ha/available
acl tx_cypher_endpoint var(txn.tx_cypher_endpoint),bool
stick-table type integer size 1k expire 10m
stick match path,word(4,/) if tx_cypher_endpoint
stick store-response hdr(Location),word(6,/) if tx_cypher_endpoint
server s1 192.168.0.10:7474 maxconn 32 check
server s2 192.168.0.11:7474 maxconn 32 check
server s3 192.168.0.12:7474 maxconn 32 check
Question #2: is the above setup the most elegant approach or is there a simpler setup possible?
Question #3: how can I see what's going on internally in haproxy, e.g. what values get stored in a variable or in a stick table? Is the stats socket
the way to go? Or is there a more verbose console output than using -d
?