How to effectively simulate "offline" mode in dev mode

I am writing some offline-first features for my app and I found, that it does not simulate the offline mode for the DDP connection.

Setting in my chrome dev tools -> network tab -> offline checkbox to true, I will only get a connection error for assets (like favicon):

GET http://localhost:7070/collection/favicon.png?v1 net::ERR_INTERNET_DISCONNECTED

…but it does not affect the DDP connection. Meteor.status() does not change at all and I can just use the pub/sub as if I am online.

I think this has to do something with the built-in proxy but I can’t really find out in the docs how to simulate offline mode here without cancelling the app.

The problem with cancelling the app process is, that on restart the page is force-reloaded and I can’t effectively simulate a data sync on reconnect.

Any experiences to share about this issue?

Edit:

The WS section in the network tab also shows frequent ongoing ping pong messages, so WS is still running.

I think chrome dev tools doesn’t simulate web sockets throttle, there is an open issue on this here, I think Firefox works but I’ve not tested it.

Thank you, I just tested Firefox -> File -> Work offline but it doesn’t work for WS neither :-/

I will check on that and if I find a solution I will post it here.

Edit:

added a potential gist to checkout on how to throtttle WS on linux: https://gist.github.com/mustafaturan/47268d8ad6d56cadda357e4c438f51ca

1 Like

How about Meteor.disconnect()?

1 Like

Thank you. I looked it up in the docs:

Call this method to disconnect from the server and stop all live data updates. While the client is disconnected it will not receive updates to collections, method calls will be queued until the connection is reestablished, and hot code push will be disabled.

This sounds to me more like a directed disconnect where everything else has a defined behavior. In the case of my app, the disconnect will happen on the network level (bad connection, rural area). Unless the app will behave as described above when forced disconnect, I think my tests will not cover it using Meteor.disconnect.

Nevertheless, I will give it a try and compare it with my staging environment. If this turns out to work I will let you know.

You can simulate disconnected websockets, but only if they are disconnected from the start, so in dev tools if you disable the network, then refresh the page, your web sockets should be disconnected. However, you can’t have any open tabs at the same time - if you have the app open in a different tab, with a live websocket, then the websocket in your current tab will also work - this is very odd functionality, and took us a long time to figure out.

Of course, this means that you can only test offline if you have service workers to cache the html/js bundle.

Kill the node process using kill -9. This is different than an interrupt with Ctrl+C.

I don’t know the operating system you’re using, but socat can help in such cases:

socat tcp-listen:6000,fork,reuseaddr tcp:localhost:3000 

This opens a listening socket on port 6000 and redirects all traffic to localhost:3000 (your Meteor development server).

After starting this, you can point the browser to http://localhost:6000. If you want to simulate the offline state, just stop the process by Ctrl+C. To switch back to online, start the above command again.

I’ve just tried this on my Linux machine. In case of Ubuntu/Linux Mint/Debian, you can install socat by

sudo apt install socat

Good luck!

2 Likes

:star_struck: Thanks a lot, sounds very reasonable. I will try it out and let you know.

Hi there,

thanks for the tipp! I tried it out. For me it does NOT work. If I kill the socat process my client is still connected and receives updates. In chrome I can see a Websocket “switching protocolls“ message. Maybe Meteors-WS system is smart enough to skip the socat bridge and start talking to the original WS-Server at port :3000?

Anyone else has an idea how to simulate that the client goes offline on localhost?

So basically I’d like to have a setup on localhost with 2 browsers and I’d love to simulate that 1 browser goes OFFLINE (and later online again), while the other browser stays ONLINE.

Any ideas?

I’ve tried it out again, learned, that port 6000 ist blocked by Chromium (ERR_UNSAFE_PORT), so I switched to port 3300:

socat tcp-listen:3300,fork,reuseaddr tcp:localhost:3000

After terminating socat, the connection is gone, I see the errors in the developer toolbar (Meteor tries to recreate the sockjs connection on port 3300, but gets ERR_CONNECTION_REFUSED). My application shows the connection error spinner, as Meteor.status().connected is false.
So, according to my tests, the recipe is still valid.

@thebarty Try to investigate on this issue using the developer toolbar. What connections are open before and after killing the TCP proxy provided by socat? Do you open the application using http://localhost:3300 or do you configure the port in another way?

If it would be the case, that the Meteor application returns to port 3000 automatically, you could start it on e. g. port 3500:

meteor run -p 3500

and use socat as proxy for the original port:

socat tcp-listen:3000,fork,reuseaddr tcp:localhost:3500

Which OS do you use?

Another possibility is blocking using iptables:

# add rule to drop packets directed to Meteor on 127.0.0.1
sudo iptables -I INPUT 1 -p TCP -d 127.0.0.1 --dport 3000 -j DROP

# remove rule
sudo iptables -D INPUT 1

After activating the rule, the connection http://127.0.0.1:3000 doesn’t work anymore, but a second browser tab on http://127.0.0.2:3000 is still active.