Class: ActiveStorage::Service::MirrorService

Inherits:
ActiveStorage::Service show all
Defined in:
lib/active_storage/service/mirror_service.rb

Overview

Active Storage Mirror Service

Wraps a set of mirror services and provides a single ActiveStorage::Service object that will all have the files uploaded to them. A primary service is designated to answer calls to:

  • download

  • exists?

  • url

  • url_for_direct_upload

  • headers_for_direct_upload

Instance Attribute Summary collapse

Attributes inherited from ActiveStorage::Service

#name

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from ActiveStorage::Service

#compose, configure, #download, #download_chunk, #exist?, #headers_for_direct_upload, #open, #public?, #update_metadata, #url, #url_for_direct_upload

Constructor Details

#initialize(primary:, mirrors:) ⇒ MirrorService

Returns a new instance of MirrorService.



31
32
33
34
35
36
37
38
39
40
# File 'lib/active_storage/service/mirror_service.rb', line 31

def initialize(primary:, mirrors:)
  @primary, @mirrors = primary, mirrors
  @executor = Concurrent::ThreadPoolExecutor.new(
    min_threads: 1,
    max_threads: mirrors.size,
    max_queue: 0,
    fallback_policy: :caller_runs,
    idle_time: 60
  )
end

Instance Attribute Details

#mirrorsObject (readonly)

Returns the value of attribute mirrors.



16
17
18
# File 'lib/active_storage/service/mirror_service.rb', line 16

def mirrors
  @mirrors
end

#primaryObject (readonly)

Returns the value of attribute primary.



16
17
18
# File 'lib/active_storage/service/mirror_service.rb', line 16

def primary
  @primary
end

Class Method Details

.build(primary:, mirrors:, name:, configurator:, **options) ⇒ Object

Stitch together from named services.



22
23
24
25
26
27
28
29
# File 'lib/active_storage/service/mirror_service.rb', line 22

def self.build(primary:, mirrors:, name:, configurator:, **options) # :nodoc:
  new(
    primary: configurator.build(primary),
    mirrors: mirrors.collect { |mirror_name| configurator.build mirror_name }
  ).tap do |service_instance|
    service_instance.name = name
  end
end

Instance Method Details

#delete(key) ⇒ Object

Delete the file at the key on all services.



52
53
54
# File 'lib/active_storage/service/mirror_service.rb', line 52

def delete(key)
  perform_across_services :delete, key
end

#delete_prefixed(prefix) ⇒ Object

Delete files at keys starting with the prefix on all services.



57
58
59
# File 'lib/active_storage/service/mirror_service.rb', line 57

def delete_prefixed(prefix)
  perform_across_services :delete_prefixed, prefix
end

#mirror(key, checksum:) ⇒ Object

Copy the file at the key from the primary service to each of the mirrors where it doesn’t already exist.



66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/active_storage/service/mirror_service.rb', line 66

def mirror(key, checksum:)
  instrument :mirror, key: key, checksum: checksum do
    if (mirrors_in_need_of_mirroring = mirrors.select { |service| !service.exist?(key) }).any?
      primary.open(key, checksum: checksum) do |io|
        mirrors_in_need_of_mirroring.each do |service|
          io.rewind
          service.upload key, io, checksum: checksum
        end
      end
    end
  end
end

#mirror_later(key, checksum:) ⇒ Object

:nodoc:



61
62
63
# File 'lib/active_storage/service/mirror_service.rb', line 61

def mirror_later(key, checksum:) # :nodoc:
  ActiveStorage::MirrorJob.perform_later key, checksum: checksum
end

#upload(key, io, checksum: nil, **options) ⇒ Object

Upload the io to the key specified to all services. The upload to the primary service is done synchronously whereas the upload to the mirrors is done asynchronously. If a checksum is provided, all services will ensure a match when the upload has completed or raise an ActiveStorage::IntegrityError.



45
46
47
48
49
# File 'lib/active_storage/service/mirror_service.rb', line 45

def upload(key, io, checksum: nil, **options)
  io.rewind
  primary.upload key, io, checksum: checksum, **options
  mirror_later key, checksum: checksum
end