You call a microflow from your browser, wait about a minute for it to finish and get the error ‘Connection dropped by intermediate host. HTTP error 504: timeout’. The strange thing is, you can’t reproduce it locally. Sounds familiar? We have been getting some reports of this issue, which is actually easy to solve.
What happens when you execute a microflow from your browser? The web is based on HTTP, which is a request-response protocol. Your browser is the client, the other party is the server (usually a machine in a data center). For every request from the client, the server must send a single response. The sooner the better, as the client is actively waiting for it.
We are, however, getting off track. Let’s look at how microflows are executed in Mendix using a single request-response message pair.
Calling microflows – the simple implementation
When you think about a microflow call, you’ll see that it has input from the client and output from the server. It makes sense then, to use HTTP’s request-response architecture to build a simple implementation of executing a microflow. Your request will look like this: “Execute microflow X with parameters this and that and return the output”. While the server is executing this microflow, your browser will wait for the HTTP-response that contains the output. This whole process will probably happen within a fraction of a second, and once the request is calculated and sent by the server and received by the client, the deal is done. So far so good.
But what if your microflow takes a long time to complete? Like one that changes thousands of objects in the database? Or one that calculates the smallest distance a travelling salesman can travel to visit all cities? This can take hours! Meanwhile, the browser that prompted the microflow is still waiting for the HTTP-response. If you were the browser you might be starting to wonder whether the server ever received your request.
You might be interested to know that you can easily verify the way this works. If you open the developer tools of your browser you can get a network packet overview. This happens to be my Chrome browser talking to a Mendix Server:
The upper request in the log is in fact a microflow call, which lasts for about six seconds.
Asynchronicity to the rescue
While the simple implementation of calling microflows is fast, easy to understand and has virtually no overhead, it is not suitable for microflows that need more than just a couple of seconds to execute. Generally speaking, if your microflow can take longer than five seconds, you should call it in an asynchronous fashion.
How? Well, like this:
Note that asynchronous calls take more than a couple of seconds and therefore always have a progress bar.
“Ok, great”, you’ll say. “But why did it go wrong in the first place and why does this fix it?”
The interfering web server
Whenever you run a Mendix Runtime in a hosted environment, you will want to run a general purpose web server like Apache or Nginx in front of the Mendix Runtime Server. The web server will catch all HTTP-requests from the client and takes care of static files by itself (Nginx is especially good at that). The other requests are forwarded (reverse-proxied) to the Mendix Runtime. When the Runtime replies to the web server, the web server passes the reply on to the client.
This will work flawlessly when the Runtime replies within a couple of seconds. However, after that, most web servers will start to get impatient. After 60 seconds* without a response from the Mendix Runtime, the web server will take matters into its own hands and reply to the client with a HTTP timeout.
When you deploy your project directly from the Modeler, there is no intermediate web server to raise timeouts. All requests go to the Runtime directly. Therefore, not surprisingly, you will not come across timeout errors in local deployment.
* depending on your configuration
What asynchronous calling does
Instead of the microflow call and its output being handled by a single HTTP request/response pair, asynchronous calling uses multiple message pairs. The first will give the command (execute microflow X). The server will reply with “Ok, I started X”. From that point on, the client will send “Is X done yet?” every couple of seconds. The reply to these requests will be either “No” or “Yes, here are the results for X!”
See for yourself:
Now you know when to trigger your microflows in a synchronous way and when to use the asynchronous way.
Asynchronous calling, pros:
- HTTP messages will be handled very quickly.
- The client is always aware of what the the Runtime is doing.
- Overhead of multiple messages per microflow call.
- A time window in which the microflow is ready, but the client has not fetched the results.
If you are not working with a lot of data or heavy computing, synchronous calling will probably suffice. Keep in mind that data tends to accumulate and microflows that once were quick might slow down. Once you start noticing that your calls take longer than five seconds, change your call type to asynchronous in the next release of your app.
There is a scenario where long outstanding HTTP-requests (of about 50 seconds) are very useful. Actually, if you go to https://home.mendix.com and inspect the network traffic with your browser’s developer tools, you will see some of them come by with stunning regularity. Can you guess what their use is?