Fix timeout issue by calling new cloud functions with part of the work.

This commit is contained in:
James Grugett 2022-04-30 16:00:29 -04:00
parent 8b9239c01b
commit b51a042c4f
3 changed files with 38 additions and 12 deletions

View File

@ -9,10 +9,7 @@ import { User } from '../../../common/user'
import { batchedWaitAll } from '../../../common/util/promise' import { batchedWaitAll } from '../../../common/util/promise'
import { Contract } from '../../../common/contract' import { Contract } from '../../../common/contract'
import { updateWordScores } from '../update-recommendations' import { updateWordScores } from '../update-recommendations'
import { import { getFeedContracts, doUserFeedUpdate } from '../update-user-feed'
getFeedContracts,
updateFeed as updateUserFeed,
} from '../update-user-feed'
const firestore = admin.firestore() const firestore = admin.firestore()
@ -31,7 +28,7 @@ async function updateFeed() {
console.log('Updating recs for', user.username) console.log('Updating recs for', user.username)
await updateWordScores(user, contracts) await updateWordScores(user, contracts)
console.log('Updating feed for', user.username) console.log('Updating feed for', user.username)
await updateUserFeed(user, feedContracts) await doUserFeedUpdate(user, feedContracts)
}) })
) )
} }

View File

@ -9,22 +9,40 @@ import { User } from '../../common/user'
import { ClickEvent } from '../../common/tracking' import { ClickEvent } from '../../common/tracking'
import { getWordScores } from '../../common/recommended-contracts' import { getWordScores } from '../../common/recommended-contracts'
import { batchedWaitAll } from '../../common/util/promise' import { batchedWaitAll } from '../../common/util/promise'
import { callCloudFunction } from './call-cloud-function'
const firestore = admin.firestore() const firestore = admin.firestore()
export const updateRecommendations = functions.pubsub export const updateRecommendations = functions.pubsub
.schedule('every 24 hours') .schedule('every 24 hours')
.onRun(async () => { .onRun(async () => {
const users = await getValues<User>(firestore.collection('users'))
const batchSize = 100
const userBatches: User[][] = []
for (let i = 0; i < users.length; i += batchSize) {
userBatches.push(users.slice(i, i + batchSize))
}
for (const batch of userBatches) {
await new Promise((resolve) => setTimeout(resolve, 100))
callCloudFunction('updateRecommendationsBatch', { users: batch })
}
})
export const updateRecommendationsBatch = functions.https.onCall(
async (data: { users: User[] }) => {
const { users } = data
const contracts = await getValues<Contract>( const contracts = await getValues<Contract>(
firestore.collection('contracts') firestore.collection('contracts')
) )
const users = await getValues<User>(firestore.collection('users'))
await batchedWaitAll( await batchedWaitAll(
users.map((user) => () => updateWordScores(user, contracts)) users.map((user) => () => updateWordScores(user, contracts))
) )
}) }
)
export const updateWordScores = async (user: User, contracts: Contract[]) => { export const updateWordScores = async (user: User, contracts: Contract[]) => {
const [bets, viewCounts, clicks] = await Promise.all([ const [bets, viewCounts, clicks] = await Promise.all([

View File

@ -14,22 +14,33 @@ import {
import { Bet } from '../../common/bet' import { Bet } from '../../common/bet'
import { Comment } from '../../common/comment' import { Comment } from '../../common/comment'
import { User } from '../../common/user' import { User } from '../../common/user'
import { batchedWaitAll } from '../../common/util/promise'
import { getContractScore } from '../../common/recommended-contracts' import { getContractScore } from '../../common/recommended-contracts'
import { callCloudFunction } from './call-cloud-function'
const firestore = admin.firestore() const firestore = admin.firestore()
const MAX_FEED_CONTRACTS = 75 const MAX_FEED_CONTRACTS = 75
export const updateUserFeed = functions.pubsub export const updateFeed = functions.pubsub
.schedule('every 60 minutes') .schedule('every 60 minutes')
.onRun(async () => { .onRun(async () => {
const contracts = await getFeedContracts() const contracts = await getFeedContracts()
const users = await getValues<User>(firestore.collection('users')) const users = await getValues<User>(firestore.collection('users'))
await batchedWaitAll(users.map((user) => () => updateFeed(user, contracts))) for (const user of users) {
await new Promise((resolve) => setTimeout(resolve, 10))
callCloudFunction('updateUserFeed', { user, contracts })
}
}) })
export const updateUserFeed = functions.https.onCall(
async (data: { contracts: Contract[]; user: User }) => {
const { user, contracts } = data
await doUserFeedUpdate(user, contracts)
}
)
export async function getFeedContracts() { export async function getFeedContracts() {
// Get contracts bet on or created in last week. // Get contracts bet on or created in last week.
const contracts = await Promise.all([ const contracts = await Promise.all([
@ -56,7 +67,7 @@ export async function getFeedContracts() {
return contracts return contracts
} }
export const updateFeed = async (user: User, contracts: Contract[]) => { export const doUserFeedUpdate = async (user: User, contracts: Contract[]) => {
const userCacheCollection = firestore.collection( const userCacheCollection = firestore.collection(
`private-users/${user.id}/cache` `private-users/${user.id}/cache`
) )