Can only use http, but not websocket

Hello,

As I have deployed my app to debian server using edeliver, I’ve noticed that connecting using websocket returnsSocketTimeoutException so, I’ve tested the server via wscat as here:

$ wscat -c ws://52.59.211.239:4001
error: Error: unexpected server response (200)
> %                                                        

while, I was expecting a response like:

HTTP/1.1 101 Switching Protocols

Has anyone faced this issue? I’ve already connected to my app locally at Mac, but I have this issue only at cloud.

1 Like

You need to tell us more about your deployment. In particular - do you have anything between client and your Cowboy server? Say, a proxy or load balancer?

1 Like

No, I have to load balancer or proxy, I can visit the server at http only currently, you can check http://52.59.211.239:4001

1 Like
  • Does it work locally?
  • In which environment are you running?
  • Whats the path you specified in your endpoint?
  • Can you post your configuration for the environment you are running in?
1 Like

It does work locally.
For cloud, in prod env
What’s the path you specified in your endpoint? I use socket/websocket

Here is my config files:
https://gist.github.com/hopewise/369896a33c924df45527df2410eabd0a

I tried with load balancer and without load balancer, did not work at cloud.
I hope I can get a clue!

1 Like

There should be a file lib/<appname>/endpoint.ex, in it there should be a line socket "/socket", AppName.UserSocket.

But since it works in dev I do think this line does exist.

But, the config.exs you provide is a bit quirky. Importing other environments configuration should happen at the very bottom of the file as stated in a comment right in the middle of your config.

Also you are relying on an environment variable SERVER at compile time. Is this really available at the machine you are compiling the release on? I do think it would be better to put this line into a proper environments configuration unconditionally. You do already have this line in config.prod.exs though…

So one thing remains open, how do you deploy?

Do you use some deployment tool? Do you build OTP-releases? Do you push-to-and-compile-on-server?

1 Like

Yes, lib/<appname>/endpoint.ex does exist, socket "/socket", AppName.UserSocket exists too

I have imported environments configuration at the very bottom of the file now.
I’ve removed the need of using environment variable SERVER, it’s used just to do config :phoenix, :serve_endpoints, true , which shall be true for production, because I do use edeliver which states that:

The Erlang runtime (OTP) and the Elixir runtime are packaged with the release—you do not have to install Erlang or Elixir separately on your production/staging servers.

As I use edeliver then its OTP-releases, right?

edeliver will build a release locally and then deploy it, as in logs:

==> Release successfully built!
You can run it in one of the following ways:
Interactive: _build/prod/rel/myapp/bin/myapp console
Foreground: _build/prod/rel/myapp/bin/myapp foreground
Daemon: _build/prod/rel/myapp/bin/myapp start
-----> Copying release 0.0.1 to local release store
-----> Copying myapp.tar.gz to release store
-----> Deploying version 0.0.1 to production hosts
-----> Authorizing hosts
-----> Uploading archive of release 0.0.1 from local release store
copying .deliver/releases/myapp_0.0.1.release.tar.gz to admin@52.59.211.239:/home/admin/myapp/myapp_0.0.1.tar.gz
copying .deliver/releases/myapp_0.0.1.release.tar.gz to admin@52.59.217.171:/home/admin/myapp/myapp_0.0.1.tar.gz
-----> Extracting archive myapp_0.0.1.tar.gz

here is the full log: there is an error in rebar.config.script, but I doubt its the reason of not connecting to ws
https://gist.github.com/hopewise/6ae493f38afb94910c7e824f4732d626

1 Like

Assuming your socket line in your endpoint is socket "/socket" then should the above be:

wscat -c ws://52.59.211.239:4001/socket

Or so? Without the /socket you are requesting the homepage yes?

1 Like

Testing locally, using /socket/websocket

wscat -c ws://192.168.1.23:4000/socket/websocket?token=Bearer%20eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE3OTgxMjkzMDYsInN1YiI6MSwidXNlcl9pZCI6MSwib3duZXJfaWQiOm51bGx9.Eo-K9VWD8fRrMcc8e0GoFYOi1bT0EoQhN7CWWcrjZEo

but I get error no matches found: ws://192.168.1.23:4000/socket/websocket?token=Bearer%20eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE3OTgxMjkzMDYsInN1YiI6MSwidXNlcl9pZCI6MSwib3duZXJfaWQiOm51bGx9.Eo-K9VWD8fRrMcc8e0GoFYOi1bT0EoQhN7CWWcrjZEo

Is the exact url I use on android to connect locally and it work fine.

If I try to connect to cloud from android, using ws://52.59.211.239:4001/socket/websocket I get error:

W/Socket: WebSocket connection error
java.net.SocketTimeoutException
at java.net.PlainSocketImpl.read(PlainSocketImpl.java:488)
at java.net.PlainSocketImpl.access$000(PlainSocketImpl.java:37)
at java.net.PlainSocketImpl$PlainSocketInputStream.read(PlainSocketImpl.java:237)
at okio.Okio$2.read(Okio.java:139)
at okio.AsyncTimeout$2.read(AsyncTimeout.java:211)
at okio.RealBufferedSource.indexOf(RealBufferedSource.java:306)
at okio.RealBufferedSource.indexOf(RealBufferedSource.java:300)
at okio.RealBufferedSource.readUtf8LineStrict(RealBufferedSource.java:196)
at com.squareup.okhttp.internal.http.Http1xStream.readResponse(Http1xStream.java:186)
at com.squareup.okhttp.internal.http.Http1xStream.readResponseHeaders(Http1xStream.java:127)
at com.squareup.okhttp.internal.http.HttpEngine.readNetworkResponse(HttpEngine.java:737)
at com.squareup.okhttp.internal.http.HttpEngine.readResponse(HttpEngine.java:573)
at com.squareup.okhttp.Call.getResponse(Call.java:287)
at com.squareup.okhttp.Call$ApplicationInterceptorChain.proceed(Call.java:243)
at com.squareup.okhttp.Call.getResponseWithInterceptorChain(Call.java:205)
at com.squareup.okhttp.Call.access$100(Call.java:35)
at com.squareup.okhttp.Call$AsyncCall.execute(Call.java:171)
at com.squareup.okhttp.internal.NamedRunnable.run(NamedRunnable.java:33)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
at java.lang.Thread.run(Thread.java:818)

So, how to debug this?

1 Like

Run locally in prod mode to check if it’s server or config.

1 Like

Great, I got this error locally testing with prod env:

W/Socket: WebSocket connection error
java.net.SocketTimeoutException

Now, I am sure, its from my app not from cloud server, but where to find the root cause of error?! As its already working fine with dev env locally.

1 Like

In the prod configuration does the site url match the url being referred from (defaults to the url value as I recall, but uncertain)?

1 Like

in prod configuration, its working locally now, using localhost:4001/socket, or rt.myapp.com/socket, it seems that its working locally on prod env no matter what is phoenix_host_url in:

config :myapp,
  phoenix_host_url: "ws://localhost:4001",

however, it worked locally only after I did mix clean

Here is how I deploy my app to cloud:

mix edeliver update production --branch=master --clean-deploy --verbose --auto-version=revision
mix edeliver restart production

So, I am still stuck, I can not use websockets for phoenix on the cloud, I keep getting timeout error, I tried everything for phoenix_host_url it does not help :frowning:

1 Like

Okay, even if --clean-deploy should do it already for you, lets try out the following:

  • stop your app
  • delete your app
  • deploy your app
  • start your app

This way we should be sure, that there really isn’t anything left from previous code.

1 Like

Congratulate me! I have fixed the problem :slight_smile: by using https://github.com/onkel-dirtus/logger_file_backend to invetigate.

My problem was related to this question: http://stackoverflow.com/questions/35888575/mix-env-0-equivalent-in-production-env

2 Likes

Tell us more? What sort of code you wrote that dependent on Mix.env? So we may avoid this trap ourselves in future :slight_smile:

2 Likes

The error log I got was:

[error] an exception was raised:
** (UndefinedFunctionError) function Mix.env/0 is undefined (module Mix is not available)
Mix.env()

I was just reading the env:

if Mix.env == :dev do ..

it work only at dev env, if I try prod, I will get the error above, and what confused me is that I got timeout error for websocket, but the truth was an error in the topic join method, making the client waits for ever… leading to timeout then.

so, what I did is not using Mix.env but only Application.get_env and define what I want in different values in dev.exs or prod.exs

1 Like

Yeah, you should not use Mix.env at runtime (only use it at compile-time).

This is precisely because you may not have Mix installed. This is the case when you do a edeliver release.

Setting up logging definitely helps to debug such issues :smiley:

3 Likes