Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

503 error from twitter api #11

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 18 additions & 4 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ const {
upsertTimeEntry,
getNumbersFromTweet,
getLastEnteredTweetId,
upsertLatestEnteredTweetId, getTotalCampaignMinutes
upsertLatestEnteredTweetId, getTotalCampaignMinutes, upsertTimeEntryWeekly, clearWeeklyData
} = require("./src/service/campaignService");
const {mongodb} = require("./src/service/mongodbService");

Expand Down Expand Up @@ -103,9 +103,12 @@ async function runCampaign(req, res) {
// Need to have someone investigate what's going on
await mongodb.connect();

const {total} = await upsertTimeEntry(tweet.twitterUserId, tweet.number, username);
const [cumulativeResponse, weeklyResponse] = await Promise.all([
upsertTimeEntry(tweet.twitterUserId, tweet.number, username),
upsertTimeEntryWeekly(tweet.twitterUserId, tweet.number, username)
]);
const communityTotal = await getTotalCampaignMinutes();
await replyToTweet(tweet.id, `Your entry has been logged. You have logged ${total} total minutes! The community has logged ${communityTotal} minutes toward our goal of one million.`);
await replyToTweet(tweet.id, `Your entry has been logged. You have logged ${cumulativeResponse.total} total minutes! The community has logged ${communityTotal} minutes toward our goal of one million.`);
});

//Update entry with the most recent tweetId so we know where to start our search next time
Expand All @@ -115,7 +118,18 @@ async function runCampaign(req, res) {
console.log("Done");
}

async function runWeeklyDataCleaner(req, res) {
console.log("Clearing weekly data...");

await mongodb.connect();

await clearWeeklyData();
await mongodb.disconnect();
res.send("Done");
}

module.exports = {
startBot,
runCampaign
runCampaign,
runWeeklyDataCleaner
}
16 changes: 13 additions & 3 deletions src/service/campaignService.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
const {mongodb} = require("./mongodbService");

async function upsertTimeEntry(authorId, amount, username) {
async function upsertTimeEntry(authorId, amount, username, collection = undefined) {
const result = await mongodb.upsert({author_id: authorId}, {
$inc: {total: parseInt(amount)},
$set: {username: username}
}, "campaign_data");
}, collection || "campaign_data");
return result.value;
}

async function upsertTimeEntryWeekly(authorId, amount, username) {
return upsertTimeEntry(authorId, amount, username, "campaign_data_weekly");
}

async function getLastEnteredTweetId() {
const result = await mongodb.findOne(undefined, undefined, "campaign_tweet_tracker");
if (!result) {
Expand All @@ -24,6 +28,10 @@ async function upsertLatestEnteredTweetId(tweetId) {
return mongodb.upsert({}, {$set: {latest_tweet_id: tweetId}}, "campaign_tweet_tracker");
}

async function clearWeeklyData() {
return mongodb.deleteByQuery({}, "campaign_data_weekly");
}

function getNumbersFromTweet(tweet) {
//Grab the number before the word " min", so they can min, mins, minutes, etc.
//'gi' is a flag that indicates case-insensitivity
Expand All @@ -45,5 +53,7 @@ module.exports = {
getNumbersFromTweet,
upsertLatestEnteredTweetId,
getLastEnteredTweetId,
getTotalCampaignMinutes
upsertTimeEntryWeekly,
getTotalCampaignMinutes,
clearWeeklyData
}
12 changes: 11 additions & 1 deletion src/service/mongodbService.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,15 @@ async function findOne(query, options, collection) {
}
}

async function deleteByQuery(query, collection) {
try {
return await client.db(dbName).collection(collection).deleteMany(query);
} catch (error) {
console.log("Failed to run deleteByQuery with the following query", query, error);
}
}


async function connect() {
try {
return await client.connect();
Expand All @@ -55,6 +64,7 @@ module.exports = {
upsert,
findOne,
disconnect,
getAggregateTotal
getAggregateTotal,
deleteByQuery
}
}
28 changes: 23 additions & 5 deletions src/service/twitterService.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,46 +7,64 @@ const twitter = new TwitterApi({
accessSecret: process.env.ACCESS_TOKEN_SECRET
});

async function search(query, lastTweetId, options = undefined) {
async function search(query, lastTweetId, options = undefined, attempts = 0) {
try {
//rate limit is 180 requests every 15 minutes
return await twitter.v2.search(query, {max_results: 100, since_id: lastTweetId, ...options});
} catch (err) {
console.error("Search failed:", err);
return retry((attemptCount) => search(query, lastTweetId, options, attemptCount + 1), 3000, attempts, err)
}
}

async function findUserById(userId, fields = undefined) {
function retry(callback, delay, attempts, err) {
console.error("Search for user failed:", err);
if (attempts >= 3) {
console.error(err);
process.exit(1);
}
return new Promise((resolve) => {
setTimeout(async () => {
console.debug("Call failed, attempt #", attempts);
await callback(attempts).then((r) => resolve(r)).finally(() => resolve());
}, delay);
});
}
async function findUserById(userId, fields = undefined, attempts = 0) {
try {
//rate limit is 900 requests every 15 minutes
return await twitter.v2.user(userId, fields);
} catch (err) {
console.error("Search for user failed:", err);
return retry((attemptCount) => findUserById(userId, fields, attemptCount + 1), 3000, attempts, err)
}
}

async function retweet(tweetId) {
async function retweet(tweetId, attempts = 0) {
try {
//rate limit is 50 requests every 15 minutes
return await twitter.v2.retweet(process.env.BOT_USER_ID, tweetId);
} catch (err) {
console.error("Retweet failed:", err);
return retry((attemptCount) => retweet(tweetId, attemptCount + 1), 3000, attempts, err)
}
}

async function getLatestRetweet(options) {
async function getLatestRetweet(options, attempts = 0) {
try {
return await twitter.v2.userTimeline(process.env.BOT_USER_ID, options);
} catch (err) {
console.error("Fetching last retweet failed:", err);
return retry((attemptCount) => getLatestRetweet(options, attemptCount + 1), 3000, attempts, err)
}
}

async function replyToTweet(tweetId, text) {
async function replyToTweet(tweetId, text, attempts = 0) {
try {
return await twitter.v2.reply(text, tweetId);
} catch (err) {
console.error("Reply failed:", err);
return retry((attemptCount) => replyToTweet(tweetId, text, attemptCount + 1), 3000, attempts, err)
}
}

Expand Down