From 456302cc6bcaf56607a11c34ee26e52022240713 Mon Sep 17 00:00:00 2001 From: benk-gc Date: Sun, 21 Apr 2024 22:12:42 +0100 Subject: [PATCH] Lazy-load client libraries. Currently when loading the gem we also implicitly load the client libraries for the bucket providers. These are quite large, and increase the time to load the gem (and the number of files included) by orders of magnitude. To avoid unnecessary slowing down the bootstrap, we can instead load these gems only if the provider is used, and memoise this on the class to avoid repeated calls to `require` (as this returns `true` when the library is first required). In testing with Rails, lazy-loading these libraries reduces the time taken for Bundler to require the gem during bootstrap from 0.25 to 0.005 seconds (yes, that's two orders of magnitude faster). --- lib/bucket_store/gcs.rb | 10 +++++++--- lib/bucket_store/s3.rb | 10 +++++++--- spec/spec_helper.rb | 1 + 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/lib/bucket_store/gcs.rb b/lib/bucket_store/gcs.rb index e4b97fe..88c387b 100644 --- a/lib/bucket_store/gcs.rb +++ b/lib/bucket_store/gcs.rb @@ -3,17 +3,21 @@ require "stringio" require "uri" -require "google/cloud/storage" - module BucketStore class Gcs DEFAULT_TIMEOUT_SECONDS = 30 + def self.load_client_library + @load_client_library ||= require "google/cloud/storage" + end + def self.build(timeout_seconds = DEFAULT_TIMEOUT_SECONDS) - Gcs.new(timeout_seconds) + new(timeout_seconds) end def initialize(timeout_seconds) + self.class.load_client_library + # Ruby's GCS library does not natively support setting up a simulator, but it allows # for a specific endpoint to be passed down which has the same effect. The simulator # needs to be special cased as in that case we want to bypass authentication, diff --git a/lib/bucket_store/s3.rb b/lib/bucket_store/s3.rb index 89b5ef3..5be5919 100644 --- a/lib/bucket_store/s3.rb +++ b/lib/bucket_store/s3.rb @@ -2,18 +2,22 @@ require "uri" -require "aws-sdk-s3" - module BucketStore class S3 DEFAULT_TIMEOUT_SECONDS = 30 + def self.load_client_library + @load_client_library ||= require "aws-sdk-s3" + end + def self.build(open_timeout_seconds = DEFAULT_TIMEOUT_SECONDS, read_timeout_seconds = DEFAULT_TIMEOUT_SECONDS) - S3.new(open_timeout_seconds, read_timeout_seconds) + new(open_timeout_seconds, read_timeout_seconds) end def initialize(open_timeout_seconds, read_timeout_seconds) + self.class.load_client_library + @storage = Aws::S3::Client.new( http_open_timeout: open_timeout_seconds, http_read_timeout: read_timeout_seconds, diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 6ae9b4d..9470f69 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,5 +1,6 @@ # frozen_string_literal: true +require "logger" require "bucket_store" RSpec.configure do |config|