Class: InvQuotaWitness
- Inherits:
-
Object
- Object
- InvQuotaWitness
- Defined in:
- app/my_lib/inv_quota_witness.rb
Overview
Class representing a QuotaWitness responsible for managing inventory quotas in Redis. This class handles the creation, tracking, and consumption of inventory quotas for ticket groups.
Instance Method Summary collapse
-
#available?(quantity, ticket_group_id) ⇒ Boolean
Checks if the specified quantity is available for a specific ID within the given ticket group.
-
#delete_keys(ticket_group_id, ids = nil) ⇒ Object
Delete specific keys by ID or all keys by ticket_group_id in Redis.
-
#generate_by_quota(ticket_group_id, quota, ticket_group = nil) ⇒ Array<String>
Generate unique IDs with a stock of 1 for the given quota and ticket group.
-
#get_data_by_restaurant_id(restaurant_id) ⇒ Array<Hash>
Retrieves available quotas from all ticket groups for a restaurant.
-
#initialize ⇒ InvQuotaWitness
constructor
Initializes a new InvQuotaWitness with Redis connection pools.
-
#pick_tickets(ticket_group_id, quantity, redis_connection = nil) ⇒ Array<String>
Picks random tickets from the quota pool for a ticket group.
-
#quota_key(ticket_group_id) ⇒ String
Creates the Redis key for storing quota information for a ticket group.
-
#quotas(ticket_group_id) ⇒ Array<String>
Retrieves all quota entries for a given ticket group.
-
#restaurant_ticket_groups_key(restaurant_id) ⇒ String
Generates the Redis key for tracking all ticket groups for a restaurant.
-
#restore_quota(ticket_group_id, tickets_to_restore) ⇒ Boolean
Restores previously consumed tickets back to the quota pool.
-
#transaction(keys) {|Redis| ... } ⇒ Object
Executes a Redis transaction on the specified keys.
-
#update_restaurant_ticket_group_list(restaurants) ⇒ void
Updates the list of ticket groups associated with restaurants in Redis.
Constructor Details
#initialize ⇒ InvQuotaWitness
Uses global $inv_redis for write operations and $inv_redis_ro for read operations.
Initializes a new InvQuotaWitness with Redis connection pools.
7 8 9 10 11 12 |
# File 'app/my_lib/inv_quota_witness.rb', line 7 def initialize # Redis connection pool for write operations on inventory quotas @redis = $inv_redis # Redis connection pool for read-only operations on inventory quotas @redis_replica = $inv_redis_ro end |
Instance Method Details
#available?(quantity, ticket_group_id) ⇒ Boolean
Checks if the specified quantity is available for a specific ID within the given ticket group.
110 111 112 113 114 |
# File 'app/my_lib/inv_quota_witness.rb', line 110 def available?(quantity, ticket_group_id) redis.with do |conn| conn.scard(quota_key(ticket_group_id)).to_i >= quantity end end |
#delete_keys(ticket_group_id, ids = nil) ⇒ Object
Delete specific keys by ID or all keys by ticket_group_id in Redis.
54 55 56 57 58 59 60 61 62 |
# File 'app/my_lib/inv_quota_witness.rb', line 54 def delete_keys(ticket_group_id, ids = nil) redis.with do |conn| if ids.present? conn.srem(quota_key(ticket_group_id), ids) else conn.del(quota_key(ticket_group_id)) end end end |
#generate_by_quota(ticket_group_id, quota, ticket_group = nil) ⇒ Array<String>
Generate unique IDs with a stock of 1 for the given quota and ticket group.
20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
# File 'app/my_lib/inv_quota_witness.rb', line 20 def generate_by_quota(ticket_group_id, quota, ticket_group = nil) return [] if quota.zero? || quota.negative? # Skip generation if ticket_group is provided and both dates have passed if ticket_group.present? max_date = [ticket_group.selling_end_date, ticket_group.valid_end_date].compact.max return [] if max_date.present? && max_date < Date.current end tickets = [] now = Time.zone.now version = "#{now.to_date}-#{now.hour}-#{now.min}" redis.with do |conn| tickets = (1..quota).map { |i| "#{ticket_group_id}-#{version}-#{i}" } conn.sadd(quota_key(ticket_group_id), tickets) # Set TTL based on max of selling_end_date and valid_end_date if ticket_group.present? max_date = [ticket_group.selling_end_date, ticket_group.valid_end_date].compact.max if max_date.present? expire_at = (max_date.to_date + 1.day).end_of_day ttl_seconds = (expire_at - Time.current).to_i conn.expire(quota_key(ticket_group_id), ttl_seconds) if ttl_seconds > 0 end end end tickets end |
#get_data_by_restaurant_id(restaurant_id) ⇒ Array<Hash>
Retrieves available quotas from all ticket groups for a restaurant.
144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 |
# File 'app/my_lib/inv_quota_witness.rb', line 144 def get_data_by_restaurant_id(restaurant_id) redis_replica.with do |conn| ticket_group_ids = conn.smembers(restaurant_ticket_groups_key(restaurant_id)) arr = fetch_ticket_groups_data(conn, ticket_group_ids) zero_inv = arr.select { |h| h[:inv].value.zero? }.pluck(:id) if arr.blank? || zero_inv.present? update_restaurant_ticket_group_list([Restaurant.fetch(restaurant_id)]) zero_inv.each do |ticket_group_id| ticket_group = TicketGroup.fetch(ticket_group_id) # Skip if ticket group is expired max_date = [ticket_group.selling_end_date, ticket_group.valid_end_date].compact.max next if max_date.present? && max_date < Date.current generate_by_quota(ticket_group_id, ticket_group.quota, ticket_group) end end arr = fetch_ticket_groups_data(conn, ticket_group_ids) arr.map do |h| quota = h[:inv].value { id: h[:id], quota: quota.to_s, } end end end |
#pick_tickets(ticket_group_id, quantity, redis_connection = nil) ⇒ Array<String>
Picks random tickets from the quota pool for a ticket group.
122 123 124 125 126 127 128 129 130 |
# File 'app/my_lib/inv_quota_witness.rb', line 122 def pick_tickets(ticket_group_id, quantity, redis_connection = nil) if redis_connection.nil? redis.with do |conn| conn.srandmember(quota_key(ticket_group_id), quantity) end else redis_connection.srandmember(quota_key(ticket_group_id), quantity) end end |
#quota_key(ticket_group_id) ⇒ String
Creates the Redis key for storing quota information for a ticket group.
68 69 70 |
# File 'app/my_lib/inv_quota_witness.rb', line 68 def quota_key(ticket_group_id) "#{namespace(ticket_group_id)}:quota" end |
#quotas(ticket_group_id) ⇒ Array<String>
Retrieves all quota entries for a given ticket group.
76 77 78 79 80 81 82 |
# File 'app/my_lib/inv_quota_witness.rb', line 76 def quotas(ticket_group_id) members = [] redis_replica.with do |conn| members = conn.smembers(quota_key(ticket_group_id)) end members end |
#restaurant_ticket_groups_key(restaurant_id) ⇒ String
Generates the Redis key for tracking all ticket groups for a restaurant.
136 137 138 |
# File 'app/my_lib/inv_quota_witness.rb', line 136 def restaurant_ticket_groups_key(restaurant_id) "RestaurantTicketGroups:#{restaurant_id}" end |
#restore_quota(ticket_group_id, tickets_to_restore) ⇒ Boolean
Restores previously consumed tickets back to the quota pool.
89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 |
# File 'app/my_lib/inv_quota_witness.rb', line 89 def restore_quota(ticket_group_id, tickets_to_restore) success = false redis.with do |conn| watch_response = conn.watch(quota_key(ticket_group_id)) do # Assuming tickets_to_restore is an array of ticket identifiers # that were originally removed from the quota set for this ticket_group. conn.multi do success = true conn.sadd(quota_key(ticket_group_id), tickets_to_restore) end end success = false if watch_response.blank? end success end |
#transaction(keys) {|Redis| ... } ⇒ Object
Executes a Redis transaction on the specified keys.
218 219 220 221 222 223 224 |
# File 'app/my_lib/inv_quota_witness.rb', line 218 def transaction(keys, &block) redis.with do |conn| conn.watch(keys) do block.call(conn) end end end |
#update_restaurant_ticket_group_list(restaurants) ⇒ void
This method returns an undefined value.
Updates the list of ticket groups associated with restaurants in Redis.
181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 |
# File 'app/my_lib/inv_quota_witness.rb', line 181 def update_restaurant_ticket_group_list(restaurants) redis.with do |conn| restaurants.each do |restaurant| ticket_groups = restaurant.ticket_groups expected_ticket_group_ids = ticket_groups.pluck(:id) next if expected_ticket_group_ids.blank? old_ticket_group_ids = conn.smembers(restaurant_ticket_groups_key(restaurant.id)) # delete old ticket groups from redis if it's not in the expected_ticket_group_ids conn.pipelined do |pipeline| old_ticket_group_ids.each do |old_ticket_group_id| unless expected_ticket_group_ids.include?(old_ticket_group_id) pipeline.srem(restaurant_ticket_groups_key(restaurant.id), old_ticket_group_id) end end pipeline.sadd(restaurant_ticket_groups_key(restaurant.id), expected_ticket_group_ids) end # Set TTL based on the max expiration date of all ticket groups max_dates = ticket_groups.map { |tg| [tg.selling_end_date, tg.valid_end_date].compact.max }.compact if max_dates.present? overall_max_date = max_dates.max expire_at = (overall_max_date.to_date + 1.day).end_of_day ttl_seconds = (expire_at - Time.current).to_i conn.expire(restaurant_ticket_groups_key(restaurant.id), ttl_seconds) if ttl_seconds > 0 end end end end |