Optimize broadcast job creation

pull/5067/head
Chocobozzz 2022-06-17 10:49:37 +02:00
parent b9e49a45f5
commit 3396e65345
No known key found for this signature in database
GPG Key ID: 583A612D890159BE
6 changed files with 49 additions and 62 deletions

View File

@ -1,6 +1,13 @@
import Bluebird from 'bluebird' import Bluebird from 'bluebird'
import { wait } from '@shared/core-utils' import { wait } from '@shared/core-utils'
import { createSingleServer, doubleFollow, PeerTubeServer, setAccessTokensToServers, waitJobs } from '@shared/server-commands' import {
createSingleServer,
doubleFollow,
killallServers,
PeerTubeServer,
setAccessTokensToServers,
waitJobs
} from '@shared/server-commands'
let servers: PeerTubeServer[] let servers: PeerTubeServer[]
const viewers: { xForwardedFor: string }[] = [] const viewers: { xForwardedFor: string }[] = []
@ -9,6 +16,7 @@ let videoId: string
run() run()
.then(() => process.exit(0)) .then(() => process.exit(0))
.catch(err => console.error(err)) .catch(err => console.error(err))
.finally(() => killallServers(servers))
async function run () { async function run () {
await prepare() await prepare()
@ -69,9 +77,13 @@ async function prepare () {
async function runViewers () { async function runViewers () {
console.log('Will run views of %d viewers.', viewers.length) console.log('Will run views of %d viewers.', viewers.length)
const before = new Date().getTime()
await Bluebird.map(viewers, viewer => { await Bluebird.map(viewers, viewer => {
return servers[0].views.simulateView({ id: videoId, xForwardedFor: viewer.xForwardedFor }) return servers[0].views.simulateView({ id: videoId, xForwardedFor: viewer.xForwardedFor })
}, { concurrency: 100 }) }, { concurrency: 100 })
console.log('Finished to run views in %d seconds.', (new Date().getTime() - before) / 1000)
await wait(5000) await wait(5000)
} }

View File

@ -3,7 +3,7 @@ import { ACTIVITY_PUB } from '@server/initializers/constants'
import { ActorModel } from '@server/models/actor/actor' import { ActorModel } from '@server/models/actor/actor'
import { VideoModel } from '@server/models/video/video' import { VideoModel } from '@server/models/video/video'
import { VideoShareModel } from '@server/models/video/video-share' import { VideoShareModel } from '@server/models/video/video-share'
import { MActorFollowersUrl, MActorLight, MActorUrl, MCommentOwner, MCommentOwnerVideo, MVideoId } from '@server/types/models' import { MActorFollowersUrl, MActorUrl, MCommentOwner, MCommentOwnerVideo, MVideoId } from '@server/types/models'
import { ActivityAudience } from '@shared/models' import { ActivityAudience } from '@shared/models'
function getOriginVideoAudience (accountActor: MActorUrl, actorsInvolvedInVideo: MActorFollowersUrl[] = []): ActivityAudience { function getOriginVideoAudience (accountActor: MActorUrl, actorsInvolvedInVideo: MActorFollowersUrl[] = []): ActivityAudience {
@ -51,13 +51,13 @@ function getAudienceFromFollowersOf (actorsInvolvedInObject: MActorFollowersUrl[
} }
async function getActorsInvolvedInVideo (video: MVideoId, t: Transaction) { async function getActorsInvolvedInVideo (video: MVideoId, t: Transaction) {
const actors: MActorLight[] = await VideoShareModel.loadActorsByShare(video.id, t) const actors = await VideoShareModel.listActorIdsAndFollowerUrlsByShare(video.id, t)
const videoAll = video as VideoModel const videoAll = video as VideoModel
const videoActor = videoAll.VideoChannel?.Account const videoActor = videoAll.VideoChannel?.Account
? videoAll.VideoChannel.Account.Actor ? videoAll.VideoChannel.Account.Actor
: await ActorModel.loadFromAccountByVideoId(video.id, t) : await ActorModel.loadAccountActorFollowerUrlByVideoId(video.id, t)
actors.push(videoActor) actors.push(videoActor)

View File

@ -19,13 +19,13 @@ async function sendVideoRelatedActivity (activityBuilder: (audience: ActivityAud
}) { }) {
const { byActor, video, transaction, contextType } = options const { byActor, video, transaction, contextType } = options
const actorsInvolvedInVideo = await getActorsInvolvedInVideo(video, transaction)
// Send to origin // Send to origin
if (video.isOwned() === false) { if (video.isOwned() === false) {
return sendVideoActivityToOrigin(activityBuilder, options) return sendVideoActivityToOrigin(activityBuilder, options)
} }
const actorsInvolvedInVideo = await getActorsInvolvedInVideo(video, transaction)
// Send to followers // Send to followers
const audience = getAudienceFromFollowersOf(actorsInvolvedInVideo) const audience = getAudienceFromFollowersOf(actorsInvolvedInVideo)
const activity = activityBuilder(audience) const activity = activityBuilder(audience)

View File

@ -1,4 +1,3 @@
import { isTestInstance } from '@server/helpers/core-utils' import { isTestInstance } from '@server/helpers/core-utils'
import { logger, loggerTagsFactory } from '@server/helpers/logger' import { logger, loggerTagsFactory } from '@server/helpers/logger'
import { VIEW_LIFETIME } from '@server/initializers/constants' import { VIEW_LIFETIME } from '@server/initializers/constants'

View File

@ -1,5 +1,5 @@
import { values } from 'lodash' import { values } from 'lodash'
import { literal, Op, Transaction } from 'sequelize' import { literal, Op, QueryTypes, Transaction } from 'sequelize'
import { import {
AllowNull, AllowNull,
BelongsTo, BelongsTo,
@ -43,15 +43,18 @@ import {
MActorAccountChannelId, MActorAccountChannelId,
MActorAPAccount, MActorAPAccount,
MActorAPChannel, MActorAPChannel,
MActorFollowersUrl,
MActorFormattable, MActorFormattable,
MActorFull, MActorFull,
MActorHost, MActorHost,
MActorId,
MActorServer, MActorServer,
MActorSummaryFormattable, MActorSummaryFormattable,
MActorUrl, MActorUrl,
MActorWithInboxes MActorWithInboxes
} from '../../types/models' } from '../../types/models'
import { AccountModel } from '../account/account' import { AccountModel } from '../account/account'
import { getServerActor } from '../application/application'
import { ServerModel } from '../server/server' import { ServerModel } from '../server/server'
import { isOutdated, throwIfNotValid } from '../utils' import { isOutdated, throwIfNotValid } from '../utils'
import { VideoModel } from '../video/video' import { VideoModel } from '../video/video'
@ -304,7 +307,10 @@ export class ActorModel extends Model<Partial<AttributesOnly<ActorModel>>> {
}) })
VideoChannel: VideoChannelModel VideoChannel: VideoChannelModel
static load (id: number): Promise<MActor> { static async load (id: number): Promise<MActor> {
const actorServer = await getServerActor()
if (id === actorServer.id) return actorServer
return ActorModel.unscoped().findByPk(id) return ActorModel.unscoped().findByPk(id)
} }
@ -312,48 +318,21 @@ export class ActorModel extends Model<Partial<AttributesOnly<ActorModel>>> {
return ActorModel.scope(ScopeNames.FULL).findByPk(id) return ActorModel.scope(ScopeNames.FULL).findByPk(id)
} }
static loadFromAccountByVideoId (videoId: number, transaction: Transaction): Promise<MActor> { static loadAccountActorFollowerUrlByVideoId (videoId: number, transaction: Transaction) {
const query = { const query = `SELECT "actor"."id" AS "id", "actor"."followersUrl" AS "followersUrl" ` +
include: [ `FROM "actor" ` +
{ `INNER JOIN "account" ON "actor"."id" = "account"."actorId" ` +
attributes: [ 'id' ], `INNER JOIN "videoChannel" ON "videoChannel"."accountId" = "account"."id" ` +
model: AccountModel.unscoped(), `INNER JOIN "video" ON "video"."channelId" = "videoChannel"."id" AND "video"."id" = :videoId`
required: true,
include: [ const options = {
{ type: QueryTypes.SELECT as QueryTypes.SELECT,
attributes: [ 'id' ], replacements: { videoId },
model: VideoChannelModel.unscoped(), plain: true as true,
required: true,
include: [
{
attributes: [ 'id' ],
model: VideoModel.unscoped(),
required: true,
where: {
id: videoId
}
}
]
}
]
}
],
transaction transaction
} }
return ActorModel.unscoped().findOne(query) return ActorModel.sequelize.query<MActorId & MActorFollowersUrl>(query, options)
}
static isActorUrlExist (url: string) {
const query = {
raw: true,
where: {
url
}
}
return ActorModel.unscoped().findOne(query)
.then(a => !!a)
} }
static listByFollowersUrls (followersUrls: string[], transaction?: Transaction): Promise<MActorFull[]> { static listByFollowersUrls (followersUrls: string[], transaction?: Transaction): Promise<MActorFull[]> {

View File

@ -3,7 +3,7 @@ import { AllowNull, BelongsTo, Column, CreatedAt, DataType, ForeignKey, Is, Mode
import { AttributesOnly } from '@shared/typescript-utils' import { AttributesOnly } from '@shared/typescript-utils'
import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub/misc' import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub/misc'
import { CONSTRAINTS_FIELDS } from '../../initializers/constants' import { CONSTRAINTS_FIELDS } from '../../initializers/constants'
import { MActorDefault } from '../../types/models' import { MActorDefault, MActorFollowersUrl, MActorId } from '../../types/models'
import { MVideoShareActor, MVideoShareFull } from '../../types/models/video' import { MVideoShareActor, MVideoShareFull } from '../../types/models/video'
import { ActorModel } from '../actor/actor' import { ActorModel } from '../actor/actor'
import { buildLocalActorIdsIn, throwIfNotValid } from '../utils' import { buildLocalActorIdsIn, throwIfNotValid } from '../utils'
@ -107,22 +107,19 @@ export class VideoShareModel extends Model<Partial<AttributesOnly<VideoShareMode
}) })
} }
static loadActorsByShare (videoId: number, t: Transaction): Promise<MActorDefault[]> { static listActorIdsAndFollowerUrlsByShare (videoId: number, t: Transaction) {
const query = { const query = `SELECT "actor"."id" AS "id", "actor"."followersUrl" AS "followersUrl" ` +
where: { `FROM "videoShare" ` +
videoId `INNER JOIN "actor" ON "actor"."id" = "videoShare"."actorId" ` +
}, `WHERE "videoShare"."videoId" = :videoId`
include: [
{ const options = {
model: ActorModel, type: QueryTypes.SELECT as QueryTypes.SELECT,
required: true replacements: { videoId },
}
],
transaction: t transaction: t
} }
return VideoShareModel.scope(ScopeNames.FULL).findAll(query) return VideoShareModel.sequelize.query<MActorId & MActorFollowersUrl>(query, options)
.then((res: MVideoShareFull[]) => res.map(r => r.Actor))
} }
static loadActorsWhoSharedVideosOf (actorOwnerId: number, t: Transaction): Promise<MActorDefault[]> { static loadActorsWhoSharedVideosOf (actorOwnerId: number, t: Transaction): Promise<MActorDefault[]> {