@adlrocha - Goxyq: Sequentializing the asynchronous
And why I'd love it to become a full-fledged open source project.
|Nov 10, 2019||2|
Today I want to share with you the reason why I embarked on the development of goxyq, a http proxy server with an embedded queue to sequentialize asynchronous and parallel calls to a system.
But first, let me give you some background: we were building a brand new blockchain-based system. The data model was based on a set of assets stored in the ledger. Due to the specifics of the use case, certain information in these assets could be modified by several users, even if they weren’t the asset owners. We had the system ready for its beta phase when we faced an “uncomfortable problem”. During our alpha tests, when two users tried to modify an asset at the same time, one of them was getting an “invalid transaction” error, and his transactions was being rejected. The reason? Two users were trying to consume the same asset at the same time, i.e. they were trying to consume as input of the transaction the same asset output. The feedback we got from users? The UX is horrible, we sometimes have to perform an operation twice for it to work, and they were right, we needed to fix this.
And you may be wondering, what blockchain platform were you using? What a weird problem to have in Ethereum. And you are right, but we weren’t using Ethereum, we used permissioned technologies, specifically BigchainDB (based on a UTXO transaction model) and Hyperledger Fabric (based on, well, based on data in a “ledger”). The thing is that the problem arised with both platforms. We approached the development teams responsible for both technologies and they acknowledged that this was actually a problem others were facing. But we couldn’t wait for them to fix it, we needed a way to have our system production-ready as promised.
Here is were goxyq came in. I decided to try the following: implementing a http proxy server with an embedded queue between the frontend and the blockchain-based backend. This proxy would inspect incoming packets and analyze if any asset was involved in the request, and its type of operation. If the operation involved the consumption of an asset output, the request would be queued to ensure that no asset outputs could be consumed at the same time, sequentializing the output consumption calls in to specific and independent queues for each asset.
Goxyq diagram (by Alfonso de la Rocha)
And where are these queues stored for Goxyq? I wanted the proxy to be as lightweight as possible, so I decided to use Redis as the storage system for the queues. Goxyq ended up doing the work, and fixing the problem we had, allowing us to put our system into production. I had to develop Goxyq in my spare time, and with a fixed deadline in mind, so it is most probably not the best piece of software you have seen lately. That’s why I decided to make the code open source in case someone else found this idea useful and wanted to evolve the project with me (if not it is a good showcase for my Github, and a demonstration of my limited programming skills :) ).
Goxyq to the rescue
Let’s see Goxyq in action. Goxyq is written in golang so be sure to have go installed before you start to play with it. You can access the code at https://github.com/adlrocha/goxyq. To install goxyq just run:
go get github.com/adlrocha/goxyq
Before we run Goxyq we need to have Redis ready for action. I suggest that you use Docker to easily run Redis. You can do this through a script I prepared in the repo:
# Go to Goxyq's repo.cd $GOXYQ_PATH# Run Redis./scripts/redis_start.sh
With Redis ready let’s run Goxyq:
# If you want to run goxyqgo run server.go# If you prefer to compile itgo build server.go./server
And we are ready to go! You can check if the proxy is alive at
/alive. But wait? We haven’t configured the proxy nor the destination endpoint yet. No problem, to easily configure this I prepared a simple config file. Go to
$GOXYQ_PATH/config/config.go. There you can modify the following variables to personalise the specifics of your goxyq:
Port: Goxyq's listening port.
DestinationHost: Destination endpoint. Where goxyq will redirect requests once analyzed and potentially queued.
ProxyPathPrefix: Prefix path for which the proxy will inspect traffic. Goxyq will only inspect traffic for requests including this specific prefix in their URL. You can use
/to inspect all traffic received.
QueueAtrribute: Body attributes that will trigger the creation of a new queue or the actual queuing of the request. This variable defines the specific attribute in the JSON body that will be inspected and responsible for the trigger.
HeaderBypass: List of headers that will be bypassed by the proxy. This allows us to bypass important headers such as authentication API keys.
And that’s all folks! There are still a lot of cool things that can be done in goxyq to make it better: implementing etcd instead of Redis for the queue storage, allowing the inspection of several body attributes for combined queues, etc. Unfortunately, I don’t have the time to do this, nonetheless goxyq has served me well already, I hope it helps you too.