#sharded bot a cron jobs
57 messages · Page 1 of 1 (latest)
• What's your exact discord.js npm list discord.js and node node -v version?
• Post the full error stack trace, not just the top part!
• Show your code!
• Explain what exactly your issue is.
• Not a discord.js issue? Check out #useful-servers.
specifically I assumed that if I call it from the sharding manager, I'm saving resources since I'm only running one timer, in stead of n timers
i have a broadcastEval call, which I'm calling from the sharding manager, and still testing for a channel within a client's scope, but it seems to replicate anyway
if(client.channels.cache.has(chan)) {
// this is the shard that has this channel
const channel = client.channels.cache.get(chan);
const objToSend = { embeds: [emb] };
channel.send(objToSend)
a channel can not exist within 2 or more clients....so I don't understand why I'm getting duplicate messages being sent, one for each shard.
bump
hi all, still looking for help here...I seem to have this problem that when I try to get a client and channel within the broadcast, all my shards seem to believe they have this channel in their client.
in this test scenario, it has 3 shards, and I see the execution of the function happen 3 times for each channel I give it....and all believe they 'have' it. how??
Do you fetch channels anywhere?
Hi Qjuh, I’ve been isolating this further. My list of channels comes from a DB. A fetch is not called prior.
What I noticed is the broadcast happens for each shard, as it should, but the client context seems to believe it owns that channel, but or rather, the channel manager’s has call seems to find the right client, so the messages duplicate
Since I’m doing this from the sharding manager directly and not from a client.shard.broadcasteval, is the behavior different?
What about events from the gateway? Do they also appear on all shards or only on one of them?
Also running the timer inside the shards would be my preferred method (get what channels are on that shard first to only schedule for them) as IPC is expensive in terms of resources too
If I run the timer inside the shard, then I’m running n-timers… all of which are duplicative. I have a timer that needs to fire 1 time per day, and send a message to a pile of channels. I don’t understand why ‘client’ in this context isn’t ‘iterating’. What I observe, is that for n-shards, I get the broadcast n-times, which is correct, but every time the client believes it has the channel ownership.
async function sendShardingMgrBasedMessage(
ch,
embed,
) {
await hwbShards.broadcastEval(async (client, { chan, emb }) => {
if(client.channels.cache.has(chan)) {
// this is the shard that has this channel
const channel = client.channels.cache.get(chan);
const objToSend = { embeds: [emb] };
// debug code
console.log('in this client! ', channel.id, ShardClientUtil.shardIdForGuildId(channel.guild.id, 3))
/*
channel.send(objToSend)
.then((newMsg) => {
})
.catch((err) => {
// eat the error, if there aren't any permissions for this, don't clog up the console
console.error(err);
});
*/
}
else {
console.log('NOT in this client! ', chan )
}
}, { context: {
chan: String(ch),
emb: embed,
} })
.catch(err => console.error(err));
}
👆?
Hmm….I haven’t tested them to answer I guess. Most of the bot’s interaction is user initiated, like a slash command
Because I get the feeling you‘re sharding wrong and all shards serve all guilds
In my above code you will see (this bot has 3 shards), the console log repeat 3 times, with the same shard id
Well that would be a problem
Then you do indeed shard wrong… show your spawn code (ShardingManager constructor and .spawn(…) call)
hwbShards = new ShardingManager('./hwb.mjs', {
totalShards: 'auto',
shardList: 'auto',
mode: 'process',
respawn: 'true',
shardArgs: [],
execArgv: ['--experimental-json-modules'],
token: token,
});
```
bot = new Client({
shards: 'auto',
intents: [
// GatewayIntentBits.GuildMessages,
GatewayIntentBits.Guilds,
GatewayIntentBits.GuildMembers,
// GatewayIntentBits.GuildMessageReactions,
],
partials: [
Partials.Channel,
Partials.Message,
Partials.User,
// Partials.Reaction,
],
makeCache: Options.cacheWithLimits({
MessageManager: 25,
PresenceManager: 0,
messageSweepInterval: 43200,
}),
messageCacheLifetime: 21600,
allowedMentions: {
parse: ['users', 'roles', 'everyone'],
repliedUser: false,
},
});
If you want auto don‘t pass anything for shardList and totalShards
And definitely don’t pass shards option in the client😳
Let the manager handle that
i added that based on a search here, because I was having trouble spawning, and this was a solution....lol
That will make your client create 3 internal shards… each
So you have 3 copies running (the same) three internal shards each.
so without this, I get this error (which is what caused me to add that to Client)
Error [ShardingRequired]: This session would have handled too many guilds - Sharding is required.
Do you require your client from your ShardingManager or vice versa?
You shouldn’t do either…
Client definition is in a contained file, that the "hwb.mjs" file listed above uses. sharding manager doesn't include it, but hwb does
i do have cases within the client where it's called
meaning a slash command for example wants to do something like client.XXX
so it imports if that's needed...is that what you're asking?
And does anything in hwb.mjs or it‘s subfiles require/import the ShardingManager?
Or do you require/import the hwb.js in your ShardingManager (not only pass it to the constructor)?
i have 1 file that imports sharding manager which doesn't have any other...and the reason I did this was because of the duplicate timers thing above....it doesn't have any other imports.
but that will, then be imported by hwb tree eventually, so that could cause the loop?
Argh, yes… you basically spawn a ShardingManager in your childprocesses that way 😳
They need to be completely seperate
hmm...yeah I get it. ok to re-think this, and get out of the cycle....you suggest I have each shard run the timer, and therefore the broadcastEval is within the client's context....right?
That won‘t solve your actual issue… fix your sharding first and foremost, then your current code should work just fine
right now I have a list of channel ID's and some of them will be on each shard/client....so I send the channel to the broadcastEval one by one, and let 'the right client' send the message to channel...in theory.
well, they're tied together, meaning instead of keeping the timer message code outside of the shard's knowledge (and then manage it through the shardingManager, I think that's the first move to decouple them....but my point is it infers redundant timers as a result.
Huh? Why don’t you run the timers in your ShardingManager file (or one you import only from there)?
ok...so I run a timer from ShardingManager. it's callback function then needs to send a message to a text channel as an action. if it's in the ShardingManager, then it doesn't understand client contexts. I'm used to calling broadcastEval from within a client's scope (e.g.) channel.client.shard.broadcastEval(...) or whatever. So here I'd need to call ShardingManager.broadcastEval(...), yes?
Yes
Well, not as static method but on the instance of ShardingManager you created
ok so I tried that originally but ended up with weird results, which led me here....so I must have some other issue wit hthat then. Let me revert to the right sharding stuff, put that back as we just discussed and I'll circle back if I have more questions.
thanks again as always Qjuh, you're a super help!
ok need a bit more advice....I feel like I'm stuck with a chicken/egg problem. If I have the shardingManager start the timer, the timer callback needs the shardingManager object to do the broadcast eval, and that makes a circular loop. What's the best practice here?
never mind I got it figured out