Search code examples
ruby-on-railssocketstcpthinunix-socket

How can I configure thin from .yml to use tcp sockets?


I have here a RoR app, what I am using with the thin appserver.

Its configuration is in an .yml file, so:

--- 
pid: /srv/cica/tmp/pids/thin.pid
group: cica
wait: 30
timeout: 30
log: /srv/cica/log/thin.log
max_conns: 1024
require: []

environment: production
max_persistent_conns: 512
servers: 4
daemonize: true
user: cica
socket: /srv/cica/tmp/thin.sock
chdir: /srv/cica

How could I use a TCP socket instead of a unix socket for listening?

The documentation I've found somehow never mentions even the possibility, although indirect references say it is possible.

The cause of the problem is that the frontend web (apache2) isn't very strong to proxying http requests to a unix path. It wouldn't be a problem with nginx.


Solution

  • In theory, you can use simply an IP:ADDR instead of the socket path:

    socket: 127.0.0.1:3000
    

    will work. But, if you use multiple thin processes, you will have a problem.

    (Which is very likely, because the whole ruby is a singlethreaded thing. Considering the IO waiting times, maybe even a significantly higher process number is also possible as the number of your CPU cores).

    Somehow the socket address decoder of the thin configuration interpreter is enough smart to use the ordinary IP address, but it increases the IP and not the port for the additional sockets. Thus, you will have multiple thin instances listening on

    # thin will listen on these addresses
    127.0.0.1:3000
    127.0.0.2:3000
    127.0.0.3:3000
    127.0.0.4:3000
    

    rather they would be listening on

    # it would be okay, but not this happens
    127.0.0.1:3000
    127.0.0.1:3001
    127.0.0.1:3002
    127.0.0.1:3003
    

    This surreal behavior is likely not what you want. (Although if you have active interfaces on all of the IPs, it could work.)

    However, this ruby thing has the nice feature that there is a direct assignment between its command line options and configuration file options. And a thin --help command will show them to you. You can enforce a TCP listening using the address and port options:

    #socket: /srv/cica/tmp/thin.sock
    address: 127.0.0.1
    port: 3000
    

    So you will get already the correct result.

    The default values are 0.0.0.0 and 3000.

    As apache wants to proxy only to a single tcp port with its most common settings (ProxyPass, ProxyPassReverse directives), also there you need some little trickery, a load balancing proxy cluster. The relevant config snippet:

    <Proxy balancer://cicas>
      BalancerMember http://localhost:3000 disablereuse=On route=cica1
      BalancerMember http://localhost:3001 disablereuse=On route=cica2
      BalancerMember http://localhost:3002 disablereuse=On route=cica3
      BalancerMember http://localhost:3003 disablereuse=On route=cica4
      ProxySet lbmethod=byrequests
    </Proxy>
    
    ProxyPass / balancer://cicas/