mirror of
https://github.com/wassname/talk.git
synced 2026-07-04 16:49:31 +08:00
fix: resolved race loading issues with dataloader (#2117)
This commit is contained in:
@@ -20,6 +20,9 @@ import {
|
||||
retrieveManyComments,
|
||||
} from "talk-server/models/comment";
|
||||
import { Connection } from "talk-server/models/connection";
|
||||
import { retrieveSharedModerationQueueQueuesCounts } from "talk-server/models/story/counts/shared";
|
||||
|
||||
import { SingletonResolver } from "./util";
|
||||
|
||||
/**
|
||||
* primeCommentsFromConnection will prime a given context with the comments
|
||||
@@ -114,4 +117,11 @@ export default (ctx: Context) => ({
|
||||
// The cursor passed here is always going to be a number.
|
||||
before: before as number,
|
||||
}).then(primeCommentsFromConnection(ctx)),
|
||||
sharedModerationQueueQueuesCounts: new SingletonResolver(() =>
|
||||
retrieveSharedModerationQueueQueuesCounts(
|
||||
ctx.mongo,
|
||||
ctx.redis,
|
||||
ctx.tenant.id
|
||||
)
|
||||
),
|
||||
});
|
||||
|
||||
@@ -11,8 +11,18 @@ import { findOrCreate } from "talk-server/services/stories";
|
||||
import { scraper } from "talk-server/services/stories/scraper";
|
||||
|
||||
export default (ctx: TenantContext) => ({
|
||||
findOrCreate: (input: FindOrCreateStoryInput) =>
|
||||
findOrCreate(ctx.mongo, ctx.tenant, input, ctx.queue.scraper),
|
||||
findOrCreate: new DataLoader(
|
||||
(inputs: FindOrCreateStoryInput[]) =>
|
||||
Promise.all(
|
||||
inputs.map(input =>
|
||||
findOrCreate(ctx.mongo, ctx.tenant, input, ctx.queue.scraper)
|
||||
)
|
||||
),
|
||||
{
|
||||
// TODO: (wyattjoh) see if there's something we can do to improve the cache key
|
||||
cacheKeyFn: (input: FindOrCreateStoryInput) => `${input.id}:${input.url}`,
|
||||
}
|
||||
),
|
||||
story: new DataLoader<string, Story | null>(ids =>
|
||||
retrieveManyStories(ctx.mongo, ctx.tenant.id, ids)
|
||||
),
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
/**
|
||||
* SingletonResolver is a cached loader for a single result.
|
||||
*/
|
||||
export class SingletonResolver<T> {
|
||||
private cache: Promise<T> | null = null;
|
||||
private resolver: () => Promise<T>;
|
||||
|
||||
constructor(resolver: () => Promise<T>) {
|
||||
this.resolver = resolver;
|
||||
}
|
||||
|
||||
public load() {
|
||||
if (this.cache) {
|
||||
return this.cache;
|
||||
}
|
||||
|
||||
const promise = this.resolver().then(result => {
|
||||
return result;
|
||||
});
|
||||
|
||||
// Set the promise on the cache.
|
||||
this.cache = promise;
|
||||
|
||||
return promise;
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
import { GQLQueryTypeResolver } from "talk-server/graph/tenant/schema/__generated__/types";
|
||||
import { retrieveSharedModerationQueueQueuesCounts } from "talk-server/models/story";
|
||||
|
||||
import { ModerationQueuesInput } from "./ModerationQueues";
|
||||
|
||||
export const Query: GQLQueryTypeResolver<void> = {
|
||||
story: (source, args, ctx) => ctx.loaders.Stories.findOrCreate(args),
|
||||
story: (source, args, ctx) => ctx.loaders.Stories.findOrCreate.load(args),
|
||||
comment: (source, { id }, ctx) =>
|
||||
id ? ctx.loaders.Comments.comment.load(id) : null,
|
||||
comments: (source, args, ctx) => ctx.loaders.Comments.forFilter(args),
|
||||
@@ -21,10 +21,6 @@ export const Query: GQLQueryTypeResolver<void> = {
|
||||
// We don't need to filter the connection, as this is tenant wide (tenant
|
||||
// filtering is completed at the model layer).
|
||||
connection: {},
|
||||
counts: await retrieveSharedModerationQueueQueuesCounts(
|
||||
ctx.mongo,
|
||||
ctx.redis,
|
||||
ctx.tenant.id
|
||||
),
|
||||
counts: await ctx.loaders.Comments.sharedModerationQueueQueuesCounts.load(),
|
||||
}),
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user