# Ruby Threads and ActiveRecord Connections

DevFeed: [Ruby Threads and ActiveRecord Connections](<https://devfeed.tech/articles/ruby-threads-and-activerecord-connections-21063.md>)

Original publisher: [Read original article](<https://jakeyesbeck.com/2016/02/14/ruby-threads-and-active-record-connections/>)

Published: 2016-02-14T12:00:00Z

Content type: tutorial

Language: en

Sources: [Jake Yesbeck](<https://devfeed.tech/sources/jake-yesbeck.md>)

Topics: [Ruby](<https://devfeed.tech/topics/ruby.md>), [Concurrent Programming](<https://devfeed.tech/topics/concurrent-programming.md>), [Concurrency](<https://devfeed.tech/topics/concurrency.md>), [Database](<https://devfeed.tech/topics/database.md>), [API](<https://devfeed.tech/topics/api.md>)

Tags: [activerecord](<https://devfeed.tech/tags/activerecord.md>), [api](<https://devfeed.tech/tags/api.md>), [concurrent-programming](<https://devfeed.tech/tags/concurrent-programming.md>), [database](<https://devfeed.tech/tags/database.md>), [ruby](<https://devfeed.tech/tags/ruby.md>)

## AI overview

This article explains how Ruby threads can process large datasets concurrently while sharing memory within a process. Using ActiveRecord, it demonstrates batched email validation through an external API and discusses the accumulation of database connections created by spawned threads.

## Source excerpt

Processing large data sets is a common problem faced by many production web applications. One solution is to divide the work amongst multiple processes and have each responsible for a single or significantly smaller batch of data. However, this solution is not without its problems. Machine provisioning limitations or financial barriers may invalidate this solution for a very large N. Within the same vein as "divide and conquer" exists another solution, one which requires far fewer parallel processes: Threads. In the Ruby programming language, a Thread is a built-in object for concurrent programming. Unlike independent processes, all Ruby Threads within the same process share memory, enabling each individual Thread to consume or process objects and elements from the same data store. For this example, a database will be queried, results manipulated and finally returned to same database via ActiveRecord. First Pass Given a User model backed by a simple users table: class User < ActiveRecord::Base end class CreateUsersTable < ActiveRecord::Migration def change create_table :users do |t| t.string :first_name t.string :last_name t.string :email t.boolean :validated, default: false t.timestamps null: false end end end The problem to solve is fairly straight forward: All User records that are not already validated should be fetched and an external API hit with their email address for validation, then saved. If a User's email address is not valid, it should be removed. Fast forwarding through time, it can be assumed that a completely serial solution has been written and deemed unsatisfactory. Then, during a second iteration, a bit of concurrent code was written: class UserEmailValidator def self.run User.where(validated: false) .find_in_batches(batch_size: 30) do |user_batch| validate_emails(user_batch) end end def self.validate_emails(user_batch) threads = user_batch.map do |user| Thread.new do email_validator = EmailService.new(user.email) email_validator.validate user.ema