chore: Move initial avatar upload to background worker (#3727)

* chore: Async user avatar upload processor

* chore: Async team avatar upload

* Refactor to task for retries

* Docs
Include avatarUrl in task props to prevent race condition
Remove transaction around upload fetch request
This commit is contained in:
Tom Moor
2022-07-03 11:36:15 +02:00
committed by GitHub
parent 1f3a1d4b86
commit 62d9bf7105
14 changed files with 187 additions and 74 deletions

View File

@@ -61,6 +61,7 @@ async function accountProvisioner({
subdomain: teamParams.subdomain,
avatarUrl: teamParams.avatarUrl,
authenticationProvider: authenticationProviderParams,
ip,
});
} catch (err) {
throw AuthenticationError(err.message);

View File

@@ -7,6 +7,8 @@ import teamCreator from "./teamCreator";
beforeEach(() => flushdb());
describe("teamCreator", () => {
const ip = "127.0.0.1";
it("should create team and authentication provider", async () => {
env.DEPLOYMENT = "hosted";
const result = await teamCreator({
@@ -17,6 +19,7 @@ describe("teamCreator", () => {
name: "google",
providerId: "example.com",
},
ip,
});
const { team, authenticationProvider, isNewTeam } = result;
expect(authenticationProvider.name).toEqual("google");
@@ -40,6 +43,7 @@ describe("teamCreator", () => {
name: "google",
providerId: "example.com",
},
ip,
});
expect(result.team.subdomain).toEqual("myteam1");
@@ -62,6 +66,7 @@ describe("teamCreator", () => {
name: "google",
providerId: "example.com",
},
ip,
});
expect(result.team.subdomain).toEqual("myteam2");
@@ -82,6 +87,7 @@ describe("teamCreator", () => {
name: "google",
providerId: "example.com",
},
ip,
});
} catch (err) {
error = err;
@@ -109,6 +115,7 @@ describe("teamCreator", () => {
name: "google",
providerId: "allowed-domain.com",
},
ip,
});
const { team, authenticationProvider, isNewTeam } = result;
expect(team.id).toEqual(existing.id);
@@ -142,6 +149,7 @@ describe("teamCreator", () => {
name: "google",
providerId: "other-domain.com",
},
ip,
});
} catch (err) {
error = err;
@@ -164,6 +172,7 @@ describe("teamCreator", () => {
name: "Updated name",
subdomain: "example",
authenticationProvider,
ip,
});
const { team, isNewTeam } = result;
expect(team.id).toEqual(existing.id);

View File

@@ -3,7 +3,7 @@ import env from "@server/env";
import { DomainNotAllowedError, MaximumTeamsError } from "@server/errors";
import Logger from "@server/logging/Logger";
import { APM } from "@server/logging/tracing";
import { Team, AuthenticationProvider } from "@server/models";
import { Team, AuthenticationProvider, Event } from "@server/models";
import { generateAvatarUrl } from "@server/utils/avatars";
type TeamCreatorResult = {
@@ -21,6 +21,7 @@ type Props = {
name: string;
providerId: string;
};
ip: string;
};
async function teamCreator({
@@ -29,6 +30,7 @@ async function teamCreator({
subdomain,
avatarUrl,
authenticationProvider,
ip,
}: Props): Promise<TeamCreatorResult> {
let authP = await AuthenticationProvider.findOne({
where: authenticationProvider,
@@ -90,7 +92,7 @@ async function teamCreator({
}
const team = await sequelize.transaction(async (transaction) => {
return Team.create(
const team = await Team.create(
{
name,
avatarUrl,
@@ -101,6 +103,19 @@ async function teamCreator({
transaction,
}
);
await Event.create(
{
name: "teams.create",
teamId: team.id,
ip,
},
{
transaction,
}
);
return team;
});
// Note provisioning the subdomain is done outside of the transaction as

View File

@@ -102,7 +102,8 @@ export default async function userCreator({
});
// We have an existing invite for his user, so we need to update it with our
// new details and link up the authentication method
// new details, link up the authentication method, and count this as a new
// user creation.
if (invite && !invite.authentications.length) {
const auth = await sequelize.transaction(async (transaction) => {
await invite.update(
@@ -114,6 +115,21 @@ export default async function userCreator({
transaction,
}
);
await Event.create(
{
name: "users.create",
actorId: invite.id,
userId: invite.id,
teamId: invite.teamId,
data: {
name,
},
ip,
},
{
transaction,
}
);
return await invite.$create<UserAuthentication>(
"authentication",
authentication,