anycable / anycable-rails

AnyCable for Ruby on Rails applications
https://anycable.io
MIT License
499 stars 35 forks source link

Could not run Anycable on Heroku #126

Closed nmenag closed 4 years ago

nmenag commented 4 years ago

Tell us about your environment

Ruby version:

ruby 2.6.2p47

Rails version: Rails 5.2.3

anycable gem version: AnyCable v1.0.0.preview2

anycable-rails gem version:

anycable-rails', '~> 1.0.0.preview2

grpc gem version:

What did you do?

I am using deploy to Heroku using a Rails app and the another app is RPC using the builpack of anycable-go, I have the two apps attached with PG and Redis.

What did you expect to happen?

Deploy to Heroku, Work Anycable on Heroku.

What actually happened?

in my RPC app is return this error, traceback:

[2020-05-20T22:50:56.878774 #7]  INFO -- : Starting AnyCable gRPC server (pid: 7, workers_num: 30)
2020-05-20T22:50:56.879062+00:00 app[web.1]: I, [2020-05-20T22:50:56.879007 #7]  INFO -- : AnyCable version: 1.0.0.preview2 (proto_version: v1)
2020-05-20T22:50:56.879172+00:00 app[web.1]: I, [2020-05-20T22:50:56.879087 #7]  INFO -- : gRPC version: 1.28.0
2020-05-20T22:50:56.879259+00:00 app[web.1]: I, [2020-05-20T22:50:56.879204 #7]  INFO -- : Serving Rails application from ./config/environment.rb
2020-05-20T22:50:56.881684+00:00 app[web.1]: E0520 22:50:56.881646089       7 server_chttp2.cc:40]        {"created":"@1590015056.881611883","description":"Servname not supported for ai_socktype","errno":-8,"file":"src/core/lib/iomgr/resolve_address_posix.cc","file_line":108,"os_error":"Servname not supported for ai_socktype","syscall":"getaddrinfo","target_address":"https://example-app-anycable.herokuapp.com"}
2020-05-20T22:50:56.881828+00:00 app[web.1]: could not add port https://example-app-anycable.herokuapp.com to server, not sure why
palkan commented 4 years ago

You should use internal address for rpc_host in RPC server, e.g. '127.0.0.1:50051`.

Have you configured ANYCABLE_RPC_HOST env var? That could be the reason.

When you run anycable-go on the same machine as RPC server, you should use internal addresses (just use the default values).

nmenag commented 4 years ago

@palkan thank you for the response, I have for the app ANYCABLE_DEPLOYMENT=true, I have put the ANYCABLE_RPC_HOST=127.0.0.1:50051,but I have a questions here:

I didn't have these variables, so must use the default values.

Now the app works not returned any error, but no response the websocket. I am using the WebSocket native https://developer.mozilla.org/es/docs/Web/API/WebSocket, in my browser only return the subscribe.

localhost

palkan commented 4 years ago

Should I se the ANYCABLE_REDIS_URL as localhost?,

Nope, it should point to Redis instance used by both apps. You can omit this variable if you already have REDIS_URL (which is usually set by add-ons).

put ANYCABLE_RPC_HOST in RPC app?

Not necessary, it defaults to 127.0.0.1, which is fine for Heroku use case (see below).

in the RPC app also should have a dyno?

Nope. We should run WS and RPC server on the same dyno 'cause they communicate via HTTP2, and it's not supported by Heroku router.

in my browser only return the subscribe.

Check Redis URL and Redis channel configured for both apps (default should work fine).

nmenag commented 4 years ago

@palkan I believe I doing something wrong:

1 I built two apps , the first app is the Rails app that have the Procfile with the heroku-webscript, anycable gem installed, Actioncable configured and anycable configuration(anycable.yml generated via anycable gem)

2 the second app has installed heroku-anycable-go buildpack installed, I thought that this app should have the same rails code, it isn't possible have a heroku app empty(maybe I am wrong), also this app has the attached of add-ons of Redis and PostgresQL, also has the variables enviroment RAILS_ENV, ANYCABLE_DEPLOYMENT, SECRET_KEY_BASE, REDIS-URL, etc.

My websocket code :

var ws = new WebSocket('ws://second-app.herokuapp.com/cable')

    const handleUnloadWindow = () => ws.close()

    ws.onopen = function () {
      window.addEventListener('unload', handleUnloadWindow)

      ws.send(
        JSON.stringify({
          command: 'subscribe',
          identifier: `{"channel":"WebNotificationChannel", "token": "${getToken()}"}`,
        })
      )
    }

In my first app, Rails app I specified config.action_cable.url = second-app.herokuapp.com/cable'

the url generate for the second app, that same url I have specified in my websocket JS and my Actioncable configuration.

in my second app heroku configuration I tried two things, the first using Procfile dyno and without dyno specified.

how is the configuration on Heroku, manage dyno?

also I have redis_channel: "web_notification_channel" , i have a env ANYCABLE_REDIS_CHANNEL, should is the same of Actioncable?

    stream_from "web_notification_channel"
  end

thank you for you help, but am I doing something wrong?,

palkan commented 4 years ago

ANYCABLE_REDIS_CHANNEL

It's an internal AnyCable channel to broadcast message from the first app to the second one. It is not related to your application code streams.

Just remove ANYCABLE_REDIS_CHANNEL for both apps to use the default one, and that should fix the broadcasting problem.

I thought that this app should have the same rails code

Yes, it should.

nmenag commented 4 years ago

@palkan I am sorry I believe that this is my last message and close the issue.

my second app return this log:

Starting process with command `bin/heroku-web`
2020-05-22T19:33:18.686303+00:00 app[web.1]: I, [2020-05-22T19:33:18.686157 #7]  INFO -- : Starting AnyCable gRPC server (pid: 7, workers_num: 30)
2020-05-22T19:33:18.686325+00:00 app[web.1]: I, [2020-05-22T19:33:18.686285 #7]  INFO -- : AnyCable version: 1.0.0.preview2 (proto_version: v1)
2020-05-22T19:33:18.686404+00:00 app[web.1]: I, [2020-05-22T19:33:18.686334 #7]  INFO -- : gRPC version: 1.28.0
2020-05-22T19:33:18.686476+00:00 app[web.1]: I, [2020-05-22T19:33:18.686429 #7]  INFO -- : Serving Rails application from ./config/environment.rb
2020-05-22T19:33:18.689080+00:00 app[web.1]: I, [2020-05-22T19:33:18.688968 #7]  INFO -- : Broadcasting Redis channel: __anycable__
2020-05-22T19:33:18.689184+00:00 app[web.1]: I, [2020-05-22T19:33:18.689129 #7]  INFO -- : RPC server is starting...
2020-05-22T19:33:18.718839+00:00 app[web.1]: I, [2020-05-22T19:33:18.718721 #7]  INFO -- : RPC server is listening on 127.0.0.1:50051
2020-05-22T19:33:18.725361+00:00 app[web.1]: I, [2020-05-22T19:33:18.725213 #7]  INFO -- : Started command: anycable-go (pid: 47)
2020-05-22T19:33:18.728378+00:00 app[web.1]: DEPRECATION WARNING: You're using default host configuration which starts AnyCable-Go
2020-05-22T19:33:18.728379+00:00 app[web.1]: server on all available interfaces including external ones. This is about to be changed
2020-05-22T19:33:18.728380+00:00 app[web.1]: to loopback interface only in future versions. Please, consider switching to "localhost"
2020-05-22T19:33:18.728380+00:00 app[web.1]: or set "0.0.0.0" explicitly in your configuration, if you want to continue with
2020-05-22T19:33:18.728381+00:00 app[web.1]: the current behavior and supress this message.
2020-05-22T19:33:18.728497+00:00 app[web.1]: I 2020-05-22T19:33:18.728Z context=main Starting AnyCable v0.6.4 (pid: 47, open file limit: 10000)
2020-05-22T19:33:18.728676+00:00 app[web.1]: I 2020-05-22T19:33:18.728Z context=main Handle WebSocket connections at /cable
2020-05-22T19:33:18.728774+00:00 app[web.1]: I 2020-05-22T19:33:18.728Z context=main Handle health connections at /health
2020-05-22T19:33:18.730357+00:00 app[web.1]: I 2020-05-22T19:33:18.730Z context=rpc RPC pool initialized: localhost:50051
2020-05-22T19:33:18.734561+00:00 app[web.1]: I 2020-05-22T19:33:18.731Z context=http Starting HTTP server at 0.0.0.0:29718
2020-05-22T19:33:18.745422+00:00 app[web.1]: I 2020-05-22T19:33:18.745Z context=pubsub Subscribed to Redis channel: __anycable__

but to my second app I must have a dyno, because if I don't specific a dyno, return 503, because else don't start my app, I understood that the two apps use the same dyno. so the second app doesn't dyno:

anycable1

I have the attached for two apps

anycable2

using REDIS_URL for the two apps, I'm not using the REDISCLOUD addons

I forget tell you, I am using sidekiq and call the brodcast into a job and Sidekiq is using REDIS_URL.

palkan commented 4 years ago

my second app return this log:

Looks good.

So, you don't have a web server in the first app, right? Only Sidekiq? Then you can use only one application (with anycable handling web sockets) instead of two (and add Sidekiq to that app).

nmenag commented 4 years ago

@palkan yes, my rails app has two dynos the web and a Dyno for sidekiq, when I do a request to endpoint this execute a job in via sidekiq and the job execute the Actioncable broadcast