Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

using async with unlimited retries leads to lost data #198

Closed
onlynone opened this issue Aug 29, 2017 · 2 comments
Closed

using async with unlimited retries leads to lost data #198

onlynone opened this issue Aug 29, 2017 · 2 comments

Comments

@onlynone
Copy link
Contributor

The following program won't send anything to influxdb:

require 'influxdb'

influxdb = InfluxDB::Client.new(
  "foo",
  async: true,
)

influxdb.create_database

(1..8).each { |i|
  influxdb.write_point(
    "bar",
    timestamp: Time.now.to_i,
    values: {baz: i},
  )
}

This is because the default value for config.retry is -1 (infinite retries), and InfluxDB::Client.initialize will only register the code with at_exit that would flush the queue when config.retry > 0. Since the main thread (along with all the spawned worker threads) will exit immediately after pushing data onto the worker queue, all that data will be lost.

  1. Is there any way to have infinite retries and not lose data on exit with the existing code? Adding the following code seems to do the trick:

    at_exit {
        influxdb.config.retry = 0
        influxdb.stop!
    }
    

    That way I can have infinite retries during normal operation and then give the main thread one last try to send anything still on the queue when it's exiting. But that's annoying to do everywhere I use influxdb with async: true

  2. Would it make sense to change client.rb from this:

        def initialize(database = nil, **opts)
          opts[:database] = database if database.is_a? String
          @config = InfluxDB::Config.new(opts)
          @stopped = false
          @writer = find_writer
    
          at_exit { stop! } if config.retry > 0
        end
    
        def stop!
          writer.worker.stop! if config.async?
          @stopped = true
        end
    

    to this:

        def initialize(database = nil, **opts)
          opts[:database] = database if database.is_a? String
          @config = InfluxDB::Config.new(opts)
          @stopped = false
          @writer = find_writer
    
          at_exit { stop! }
        end
    
        def stop!
          if config.async?
            config.retry = 0 if config.retry < 0
            writer.worker.stop!
          end
          @stopped = true
        end
    

    That way, if you have async set and a retry greater than or equal to 0, you'll get the cleanup with retry still at that number. If you have async set and retry set to -1, the code will set it to 0 and run the cleanup, just to give the main thread one last chance to write the data.

@dmke
Copy link
Contributor

dmke commented Aug 29, 2017

Thanks for reporting this. I am on my way to bed, but I will take a look tomorrow. From a first glance, the suggested solution (2) could also be a fix for a sporadically failing test on JRuby.

I need to make sure this doesn't introduce other weirdnesses. Would you mind preparing a PR, so that Travis can perform a first sanity check? That would be great :-)

@dmke
Copy link
Contributor

dmke commented Aug 30, 2017

This looks good. I'll merge that in.

@dmke dmke closed this as completed Aug 30, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants