async def start( self, *, activity: typing.Optional[presences.Activity] = None, afk: bool = False, check_for_updates: bool = True, idle_since: typing.Optional[datetime.datetime] = None, ignore_session_start_limit: bool = False, large_threshold: int = 250, shard_ids: typing.Optional[typing.Set[int]] = None, shard_count: typing.Optional[int] = None, status: presences.Status = presences.Status.ONLINE, ) -> None: """Start the bot, wait for all shards to become ready, and then return. Other Parameters ---------------- activity : typing.Optional[hikari.presences.Activity] The initial activity to display in the bot user presence, or `builtins.None` (default) to not show any. afk : builtins.bool The initial AFK state to display in the bot user presence, or `builtins.False` (default) to not show any. check_for_updates : builtins.bool Defaults to `builtins.True`. If `builtins.True`, will check for newer versions of `hikari` on PyPI and notify if available. idle_since : typing.Optional[datetime.datetime] The `datetime.datetime` the user should be marked as being idle since, or `builtins.None` (default) to not show this. ignore_session_start_limit : builtins.bool Defaults to `builtins.False`. If `builtins.False`, then attempting to start more sessions than you are allowed in a 24 hour window will throw a `hikari.errors.GatewayError` rather than going ahead and hitting the IDENTIFY limit, which may result in your token being reset. Setting to `builtins.True` disables this behavior. large_threshold : builtins.int Threshold for members in a guild before it is treated as being "large" and no longer sending member details in the `GUILD CREATE` event. Defaults to `250`. shard_ids : typing.Optional[typing.Set[builtins.int]] The shard IDs to create shards for. If not `builtins.None`, then a non-`None` `shard_count` must ALSO be provided. Defaults to `builtins.None`, which means the Discord-recommended count is used for your application instead. shard_count : typing.Optional[builtins.int] The number of shards to use in the entire distributed application. Defaults to `builtins.None` which results in the count being determined dynamically on startup. status : hikari.presences.Status The initial status to show for the user presence on startup. Defaults to `hikari.presences.Status.ONLINE`. """ if shard_ids is not None and shard_count is None: raise TypeError( "Must pass shard_count if specifying shard_ids manually") self._validate_activity(activity) # Dispatch the update checker, the sharding requirements checker, and dispatch # the starting event together to save a little time on startup. start_time = time.monotonic() if check_for_updates: asyncio.create_task( ux.check_for_updates(self._http_settings, self._proxy_settings), name="check for package updates", ) requirements_task = asyncio.create_task( self._rest.fetch_gateway_bot(), name="fetch gateway sharding settings") await self.dispatch(lifetime_events.StartingEvent(app=self)) requirements = await requirements_task if shard_count is None: shard_count = requirements.shard_count if shard_ids is None: shard_ids = set(range(shard_count)) if requirements.session_start_limit.remaining < len( shard_ids) and not ignore_session_start_limit: _LOGGER.critical( "would have started %s session%s, but you only have %s session%s remaining until %s. Starting more " "sessions than you are allowed to start may result in your token being reset. To skip this message, " "use bot.run(..., ignore_session_start_limit=True) or bot.start(..., ignore_session_start_limit=True)", len(shard_ids), "s" if len(shard_ids) != 1 else "", requirements.session_start_limit.remaining, "s" if requirements.session_start_limit.remaining != 1 else "", requirements.session_start_limit.reset_at, ) raise errors.GatewayError( "Attempted to start more sessions than were allowed in the given time-window" ) _LOGGER.info( "planning to start %s session%s... you can start %s session%s before the next window starts at %s", len(shard_ids), "s" if len(shard_ids) != 1 else "", requirements.session_start_limit.remaining, "s" if requirements.session_start_limit.remaining != 1 else "", requirements.session_start_limit.reset_at, ) for window_start in range( 0, shard_count, requirements.session_start_limit.max_concurrency): window = [ candidate_shard_id for candidate_shard_id in range( window_start, window_start + requirements.session_start_limit.max_concurrency) if candidate_shard_id in shard_ids ] if not window: continue if self._shards: close_waiter = asyncio.create_task(self._closing_event.wait()) shard_joiners = [ asyncio.ensure_future(s.join()) for s in self._shards.values() ] try: # Attempt to wait for all started shards, for 5 seconds, along with the close # waiter. # If the close flag is set (i.e. user invoked bot.close), or one or more shards # die in this time, we shut down immediately. # If we time out, the joining tasks get discarded and we spin up the next # block of shards, if applicable. _LOGGER.info( "the next startup window is in 5 seconds, please wait..." ) await aio.first_completed( aio.all_of(*shard_joiners, timeout=5), close_waiter) if not close_waiter.cancelled(): _LOGGER.info( "requested to shut down during startup of shards") else: _LOGGER.critical( "one or more shards shut down unexpectedly during bot startup" ) return except asyncio.TimeoutError: # If any shards stopped silently, we should close. if any(not s.is_alive for s in self._shards.values()): _LOGGER.info( "one of the shards has been manually shut down (no error), will now shut down" ) return # new window starts. except Exception as ex: _LOGGER.critical( "an exception occurred in one of the started shards during bot startup: %r", ex) raise started_shards = await aio.all_of( *(self._start_one_shard( activity=activity, afk=afk, idle_since=idle_since, status=status, large_threshold=large_threshold, shard_id=candidate_shard_id, shard_count=shard_count, url=requirements.url, ) for candidate_shard_id in window if candidate_shard_id in shard_ids)) for started_shard in started_shards: self._shards[started_shard.id] = started_shard await self.dispatch(lifetime_events.StartedEvent(app=self)) _LOGGER.info("application started successfully in approx %.2f seconds", time.monotonic() - start_time)
def deserialize_started_event(self) -> lifetime_events.StartedEvent: return lifetime_events.StartedEvent(app=self._app)