Account Options

  1. Sign in
The old Google Groups will be going away soon, but your browser is incompatible with the new version.
Google Groups Home
« Groups Home
Shared database connection
There are currently too many topics in this group that display first. To make this topic appear first, remove this option from another topic.
There was an error processing your request. Please try again.
flag
  8 messages - Collapse all  -  Translate all to Translated (View all originals)
The group you are posting to is a Usenet group. Messages posted to this group will make your email address visible to anyone on the Internet.
Your reply message has not been sent.
Your post was successful
 
From:
To:
Cc:
Followup To:
Add Cc | Add Followup-to | Edit Subject
Subject:
Validation:
For verification purposes please type the characters you see in the picture below or the numbers you hear by clicking the accessibility icon. Listen and type the numbers you hear
 
David Ott  
View profile  
 More options Oct 20 2012, 11:28 am
From: David Ott <david.t....@gmail.com>
Date: Sat, 20 Oct 2012 08:28:06 -0700 (PDT)
Local: Sat, Oct 20 2012 11:28 am
Subject: Shared database connection

I am using Sequel on an application that is composed of about half a dozen
sinatra services. These services use Sequel::Model.db to connect to
postgres via some shared logic that is installed as a gem
'sequel_connection'. That connection logic is pretty simple. Here it is.

module Persistence
  module Sequel
    require 'sequel'

    module Connection
      class << self
        def _database
          @_database ||= ::Sequel.connect(connection_string)
        end

        def database
          retries = 0
          begin
            retries += 1
            _database
          rescue ::Sequel::DatabaseDisconnectError
            retry if retries > 10
          end
        end

        def connection_string
          ["postgres://"].tap do |s|
            s << config.username        if config.username
            s << ":#{config.password}" if config.password
            s << "@#{config.host}"      if config.host
            s << ":#{config.port}"         if config.port
            s << "/#{config.database}" if config.database
          end.join("")
        end

        def config
          Config.for(ENV['RACK_ENV'])
        end
      end

      require 'ostruct'
      require 'yaml'

      class Config < OpenStruct
        class << self
          attr_accessor :config_file

          def for(env)
            new(config[env])
          end

          def config
            YAML.load_file("#{config_file}")
          end
        end
      end
    end
  end
end

The services set the connections in an init script that get required in the
sinatra class as such:

require 'sequel_connection'

Persistence::Sequel::Connection::Config.config_file =
File.join('config/database.yml')
Sequel::Model.db = Persistence::Sequel::Connection.database

I am experiencing trouble with the connections dropping and not being
re-establised. The air brake error is this:

Sequel::DatabaseDisconnectError: PG::Error: SSL error: sslv3 alert bad
record mac

I assume there is some important thread safety stuff here that I am
glossing over due to my inexperience with this kind of setup. What's the
best way to deal with this? Is sharing the connection the wrong approach?
Should I nix the gem and have this logic in each service? Would wrapping it
in a Thread.new block work? Or is there something else I'm missing like
disconnecting/reconnecting properly?

Thanks for the help,
-Dave


 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Jeremy Evans  
View profile  
 More options Oct 20 2012, 12:52 pm
From: Jeremy Evans <jeremyeva...@gmail.com>
Date: Sat, 20 Oct 2012 09:52:20 -0700 (PDT)
Local: Sat, Oct 20 2012 12:52 pm
Subject: Re: Shared database connection

On Saturday, October 20, 2012 8:28:06 AM UTC-7, David Ott wrote:

> I am experiencing trouble with the connections dropping and not being
> re-establised. The air brake error is this:

> Sequel::DatabaseDisconnectError: PG::Error: SSL error: sslv3 alert bad
> record mac

> I assume there is some important thread safety stuff here that I am
> glossing over due to my inexperience with this kind of setup. What's the
> best way to deal with this? Is sharing the connection the wrong approach?
> Should I nix the gem and have this logic in each service? Would wrapping it
> in a Thread.new block work? Or is there something else I'm missing like
> disconnecting/reconnecting properly?

Sequel is thread-safe, so it's unlikely to be thread safety.  If I had to
guess, you are using a forking webserver, loading your application code
before forking, and not calling Database#disconnect before forking,
resulting in multiple processes sharing the connections.  But that's really
only a guess based on limited information.

A couple of notes based on the code you posted:

1) Also note that there is no point in building a URL in your code, just
pass an options hash to Sequel.connect.

2) Your attempts to retry are misguided.  A DatabaseDisconnectError does
not mean a problem with the Database object, but an issue with a single
connection in the Database's connection pool, which Sequel handles by
removing the connection from the pool.  Creating a new Database object is
absolutely the wrong approach.

Jeremy


 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
David Ott  
View profile  
 More options Oct 20 2012, 2:07 pm
From: David Ott <david.t....@gmail.com>
Date: Sat, 20 Oct 2012 11:07:59 -0700 (PDT)
Local: Sat, Oct 20 2012 2:07 pm
Subject: Re: Shared database connection

Jeremy,

Thanks for your comments. The retries were me grasping at straws. I figured
it wasn't helping.

I think your assumption is correct. These services are using Passenger.
Where is the best place to disconnect? I have an init.rb file that sets the
connection and that gets required in the sinatra file. Can i call
disconnect at the end of that init file?


 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Jeremy Evans  
View profile  
 More options Oct 20 2012, 6:22 pm
From: Jeremy Evans <jeremyeva...@gmail.com>
Date: Sat, 20 Oct 2012 15:22:30 -0700 (PDT)
Local: Sat, Oct 20 2012 6:22 pm
Subject: Re: Shared database connection

On Saturday, October 20, 2012 11:07:59 AM UTC-7, David Ott wrote:

> Jeremy,

> Thanks for your comments. The retries were me grasping at straws. I
> figured it wasn't helping.

> I think your assumption is correct. These services are using Passenger.
> Where is the best place to disconnect? I have an init.rb file that sets the
> connection and that gets required in the sinatra file. Can i call
> disconnect at the end of that init file?

IIRC, Passenger, unlike Unicorn, lacks a before_fork hook, so disconnecting
near the end of the application code loading is the best place.

Jeremy


 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Daniel Tsai  
View profile  
 More options Dec 2 2012, 2:01 pm
From: Daniel Tsai <dienyu.t...@gmail.com>
Date: Sun, 2 Dec 2012 11:01:35 -0800 (PST)
Local: Sun, Dec 2 2012 2:01 pm
Subject: Re: Shared database connection

I have the same problem and happened to google this thread. Is my modifed
unicorn config ok?

require 'sequel'
require 'redis'
require 'sidekiq'

worker_processes 4
preload_app true
timeout 90

before_fork do |server, worker|
  # Disconnect all database connection from Sequel
  DB.disconnect
  sleep 1
end

after_fork do |server, worker|
  # Reconnect database by Sequel
  DB = Sequel.connect(ENV['DATABASE_URL'])

  # Reconnect Redis
  $redis = Redis.new(:url => ENV['REDIS_PROVIDER'])

  # Reconnect Sidekiq Redis client
  Sidekiq.configure_client do |config|
    config.redis = { :url => ENV['REDIS_PROVIDER'], :size => 1 }
  end
end

Thanks,
Daniel


 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Jeremy Evans  
View profile  
 More options Dec 2 2012, 4:16 pm
From: Jeremy Evans <jeremyeva...@gmail.com>
Date: Sun, 2 Dec 2012 13:16:08 -0800 (PST)
Local: Sun, Dec 2 2012 4:16 pm
Subject: Re: Shared database connection

You don't need to manually call Sequel.connect after fork, so you should
remove this.  I'm not sure about Redis/Sidekiq, but the same may be true
for them, you should probably talk to those authors.


 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Daniel Tsai  
View profile  
 More options Dec 2 2012, 4:46 pm
From: Daniel Tsai <dienyu.t...@gmail.com>
Date: Sun, 2 Dec 2012 13:46:48 -0800 (PST)
Local: Sun, Dec 2 2012 4:46 pm
Subject: Re: Shared database connection

I really appreciate your quick reply and I have been a big fan of Sequel. I
just want to make sure I understand correctly that I only need to call
DB.disconnect in before_fork block and do not do anything in after_fork
block. Will DB get the connection automatically in this case?

before_fork do |server, worker|
  # Disconnect all database connection from Sequel
  DB.disconnect
  sleep 1
end

after_fork do |server, worker|
  # Do nothing here and DB will connect automatically
end


 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Jeremy Evans  
View profile  
 More options Dec 2 2012, 5:01 pm
From: Jeremy Evans <jeremyeva...@gmail.com>
Date: Sun, 2 Dec 2012 14:01:38 -0800 (PST)
Local: Sun, Dec 2 2012 5:01 pm
Subject: Re: Shared database connection

Correct.  The only part of Sequel that cannot be shared in a multiprocess
application is the underlying database socket connections.  DB.disconnect
clears the connections from the Database object's connection pool, and
doing that before forking ensures that each forked child will have its own
connections that are not shared (connections will be reestablished on an
as-needed basis in each child).

Jeremy


 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
End of messages
« Back to Discussions « Newer topic     Older topic »