Class: DiscordRDA::ShardManager

Inherits:
Object
  • Object
show all
Defined in:
lib/discord_rda/connection/shard_manager.rb

Overview

Manages sharding for large Discord bots. Automatically calculates shard count and distributes guilds.

Constant Summary collapse

GUILDS_PER_SHARD =

Maximum guilds per shard (Discord recommends 250, hard limit 2500)

1000

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(config, event_bus, logger, gateway_state: {}) ⇒ ShardManager

Initialize shard manager

Parameters:



33
34
35
36
37
38
39
40
41
42
43
# File 'lib/discord_rda/connection/shard_manager.rb', line 33

def initialize(config, event_bus, logger, gateway_state: {})
  @config = config
  @event_bus = event_bus
  @logger = logger
  @gateway_state = gateway_state || {}
  @shard_count = nil
  @shards = []
  @total_guilds = nil
  @ready = false
  @mutex = Mutex.new
end

Instance Attribute Details

#configConfiguration (readonly)

Returns Configuration instance.

Returns:



12
13
14
# File 'lib/discord_rda/connection/shard_manager.rb', line 12

def config
  @config
end

#loggerLogger (readonly)

Returns Logger instance.

Returns:

  • (Logger)

    Logger instance



15
16
17
# File 'lib/discord_rda/connection/shard_manager.rb', line 15

def logger
  @logger
end

#readyBoolean (readonly)

Returns Whether all shards are ready.

Returns:

  • (Boolean)

    Whether all shards are ready



27
28
29
# File 'lib/discord_rda/connection/shard_manager.rb', line 27

def ready
  @ready
end

#shard_countInteger (readonly)

Returns Total number of shards.

Returns:

  • (Integer)

    Total number of shards



18
19
20
# File 'lib/discord_rda/connection/shard_manager.rb', line 18

def shard_count
  @shard_count
end

#shardsArray<GatewayClient> (readonly)

Returns Active gateway clients.

Returns:



21
22
23
# File 'lib/discord_rda/connection/shard_manager.rb', line 21

def shards
  @shards
end

#total_guildsInteger (readonly)

Returns Total guilds across all shards.

Returns:

  • (Integer)

    Total guilds across all shards



24
25
26
# File 'lib/discord_rda/connection/shard_manager.rb', line 24

def total_guilds
  @total_guilds
end

Class Method Details

.shard_for_guild(guild_id, total_shards) ⇒ Integer

Get shard ID for a guild

Parameters:

  • guild_id (String, Integer)

    Guild ID

  • total_shards (Integer)

    Total shard count

Returns:

  • (Integer)

    Shard ID



68
69
70
# File 'lib/discord_rda/connection/shard_manager.rb', line 68

def self.shard_for_guild(guild_id, total_shards)
  ((guild_id.to_i >> 22) % total_shards)
end

Instance Method Details

#calculate_shard_count(requested_shards, rest_client) ⇒ Integer

Calculate or retrieve shard count

Parameters:

  • requested_shards (Array, Symbol)

    Requested shards or :auto

  • rest_client (RestClient)

    REST client for fetching session info

Returns:

  • (Integer)

    Number of shards to use



49
50
51
52
53
54
55
56
57
58
59
60
61
62
# File 'lib/discord_rda/connection/shard_manager.rb', line 49

def calculate_shard_count(requested_shards, rest_client)
  if requested_shards == :auto
    # Fetch recommended shard count from Discord
    fetch_recommended_shards(rest_client)
  elsif requested_shards.is_a?(Array) && requested_shards.length == 1 && requested_shards[0] == :auto
    fetch_recommended_shards(rest_client)
  elsif requested_shards.is_a?(Array) && requested_shards.first.is_a?(Array)
    # Explicit shard ranges provided
    requested_shards.length
  else
    # Single shard or explicit count
    requested_shards.is_a?(Array) ? requested_shards[1] : 1
  end
end

#fetch_session_info(rest_client) ⇒ Hash

Get session information from Discord

Parameters:

Returns:

  • (Hash)

    Session info with url, shards, session_start_limit



168
169
170
# File 'lib/discord_rda/connection/shard_manager.rb', line 168

def fetch_session_info(rest_client)
  rest_client.get('/gateway/bot')
end

#reconnect_shard(shard_id) ⇒ void

This method returns an undefined value.

Reconnect a specific shard

Parameters:

  • shard_id (Integer)

    Shard ID



139
140
141
142
143
144
145
146
147
# File 'lib/discord_rda/connection/shard_manager.rb', line 139

def reconnect_shard(shard_id)
  shard = shard(shard_id)
  return unless shard

  @logger&.info('Reconnecting shard', shard: shard_id)
  shard.disconnect
  sleep(@config.initial_reconnect_delay)
  shard.connect
end

#respawn(new_shard_count) ⇒ void

This method returns an undefined value.

Spawn additional shards (hot scaling)

Parameters:

  • new_shard_count (Integer)

    New total shard count



152
153
154
155
156
157
158
159
160
161
162
163
# File 'lib/discord_rda/connection/shard_manager.rb', line 152

def respawn(new_shard_count)
  return if new_shard_count <= @shard_count.to_i

  @logger&.info('Respawning with more shards', old: @shard_count, new: new_shard_count)

  # Start new shards
  ((@shard_count || 0)...new_shard_count).each do |shard_id|
    start_shard(shard_id, new_shard_count)
  end

  @shard_count = new_shard_count
end

#shard(shard_id) ⇒ GatewayClient?

Get shard by ID

Parameters:

  • shard_id (Integer)

    Shard ID

Returns:



100
101
102
# File 'lib/discord_rda/connection/shard_manager.rb', line 100

def shard(shard_id)
  @shards.find { |s| s.instance_variable_get(:@shard_id) == shard_id }
end

#shard_ready?(shard_id) ⇒ Boolean

Check if shard is ready

Parameters:

  • shard_id (Integer)

    Shard ID

Returns:

  • (Boolean)

    True if ready



125
126
127
# File 'lib/discord_rda/connection/shard_manager.rb', line 125

def shard_ready?(shard_id)
  shard(shard_id)&.connected
end

#start(shard_ids = nil) ⇒ void

This method returns an undefined value.

Start all shards

Parameters:

  • shard_ids (Array<Integer>) (defaults to: nil)

    Specific shard IDs to start (nil for all)



75
76
77
78
79
80
81
82
83
84
85
86
# File 'lib/discord_rda/connection/shard_manager.rb', line 75

def start(shard_ids = nil)
  shard_count = @shard_count || 1
  ids = shard_ids || (0...shard_count).to_a

  @logger&.info('Starting shards', count: ids.length, total: shard_count)

  ids.each do |shard_id|
    start_shard(shard_id, shard_count)
  end

  wait_for_ready
end

#statusHash

Get status of all shards

Returns:

  • (Hash)

    Status information



106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
# File 'lib/discord_rda/connection/shard_manager.rb', line 106

def status
  {
    total_shards: @shard_count,
    active_shards: @shards.length,
    ready: @ready,
    guilds: @total_guilds,
    shard_statuses: @shards.map do |s|
      {
        id: s.instance_variable_get(:@shard_id),
        connected: s.connected,
        session: s.session_id
      }
    end
  }
end

#stopvoid

This method returns an undefined value.

Stop all shards



90
91
92
93
94
95
# File 'lib/discord_rda/connection/shard_manager.rb', line 90

def stop
  @logger&.info('Stopping all shards')
  @shards.each(&:disconnect)
  @shards.clear
  @ready = false
end

#update_guild_count(count) ⇒ void

This method returns an undefined value.

Update total guild count

Parameters:

  • count (Integer)

    Total guilds



132
133
134
# File 'lib/discord_rda/connection/shard_manager.rb', line 132

def update_guild_count(count)
  @total_guilds = count
end