PinkiePie
04/03/2022, 12:18 PM125 await Promise.all([
→ 126 prisma.post.create(
Error in connector: Database error. error code: unknown, error message: Command failed (WriteConflict): WriteConflict error: this operation conflicted with another operation. Please retry your operation or multi-document transaction.)
123 | });
I'm trying to insert multiple documents:
await Promise.all([
prisma.post.create({
data: mockPost1,
}),
prisma.post.create({
data: mockPost2,
}),
prisma.post.create({
data: mockPost3,
}),
]);
which have such a shape:
export const mockPost1 = {
id: '507f1f77bcf86cd799439011',
name: 'testPost1',
description: 'testPost1 description',
author: {
connect: {
id: mockUser1.id,
},
},
};
export const mockPost2 = {
id: '507f1f77bcf86cd799439012',
name: 'testPost2',
description: 'testPost2 description',
author: {
connect: {
id: mockUser1.id,
},
},
};
export const mockPost3 = {
id: '507f1f77bcf86cd799439013',
name: 'testPost3',
description: 'testPost3 description',
author: {
connect: {
id: mockUser1.id,
},
},
};
janpio
dpetrick
04/04/2022, 10:09 AMauthor_id
is stored on the Post, then can you try writing the author_id
directly instead of connect
? I'm interested if the transactions stop overlapping in that case.millsp
04/04/2022, 9:01 PMimport { PrismaClient } from ".prisma/client"
import crypto from 'crypto'
export const user = {
email: 'email',
}
async function main() {
const prisma = new PrismaClient()
// await prisma.user.deleteMany()
// await prisma.post.deleteMany()
// await prisma.user.create({data: user})
let posts = [] as any[]
for (let i = 0; i < 100; i++) {
posts.push({
id: crypto.randomBytes(12).toString('hex'),
title: 'title',
published: true,
author: {
connect: {
email: user.email
}
}
})
}
await Promise.all(posts.map(post => prisma.post.create({ data: post })))
}
void main().catch((e) => {
console.log(e.message)
process.exit(1)
})
and schema
generator client {
provider = "prisma-client-js"
output = "../node_modules/.prisma/client"
previewFeatures = ["mongodb"]
}
datasource db {
provider = "mongodb"
url = "<mongodb://root:prisma@localhost:27018/tests2?authSource=admin>"
}
model User {
id String @default(auto()) @map("_id") @id @db.ObjectId
email String @unique
name String?
posts Post[]
}
model Post {
id String @default(auto()) @map("_id") @id @db.ObjectId
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
published Boolean
title String
content String?
authorId String?
author User? @relation(fields: [authorId], references: [id])
}
PinkiePie
04/04/2022, 9:10 PMauthor_id
didn't help, same issue. but what is more interesting, I never have this issue locally, but I always have it on CI (github actions). but i have the same docker container for mongo and the tests setup is exactly the same.PinkiePie
04/04/2022, 9:11 PMprismagraphql/mongo-single-replica:5.0.3
PinkiePie
04/04/2022, 9:13 PMPinkiePie
04/04/2022, 9:17 PMawait Promise.all([
prisma.post.create({
data: mockPost1,
}),
prisma.post.create({
data: mockPost2,
}),
prisma.post.create({
data: mockPost3,
}),
]);
to
await prisma.post.create({
data: mockPost1,
});
await prisma.post.create({
data: mockPost2,
});
await prisma.post.create({
data: mockPost3,
});
it works fine even on CImillsp
04/04/2022, 9:19 PMmillsp
04/04/2022, 9:20 PMmillsp
04/04/2022, 9:21 PMimport { PrismaClient } from ".prisma/client"
import crypto from 'crypto'
const post = {
id: crypto.randomBytes(12).toString('hex'),
title: 'title',
published: true,
}
async function main() {
const prisma1 = new PrismaClient()
const prisma2 = new PrismaClient()
void prisma1.post.create({ data: post }).then()
void prisma2.post.create({ data: post }).then()
}
void main().catch((e) => {
console.log(e.message)
process.exit(1)
})
PinkiePie
04/04/2022, 9:33 PMcrypto.randomBytes(12).toString('hex')
from the hardcoded ids - the result is the same, works fine locally, WriteConflict on the CIPinkiePie
04/04/2022, 9:39 PMgenerator client {
provider = "prisma-client-js"
previewFeatures = ["mongoDb"]
}
datasource db {
provider = "mongodb"
url = env("DATABASE_URL")
}
model Post {
id String @id @default(auto()) @map("_id") @db.ObjectId
authorId String @db.ObjectId
author User @relation(fields: [authorId], references: [id], onDelete: Cascade)
description String
name String
}
model User {
id String @id @default(auto()) @map("_id") @db.ObjectId
login String @unique
name String
posts Post[]
}
PinkiePie
04/04/2022, 9:41 PMexport const insertMockData = async () => {
await prisma.user.deleteMany({});
await prisma.post.deleteMany({});
await prisma.user.create({
data: mockUser1,
});
await Promise.all([
prisma.post.create({
data: mockPost1,
}),
prisma.post.create({
data: mockPost2,
}),
prisma.post.create({
data: mockPost3,
}),
]);
};
PinkiePie
04/04/2022, 9:42 PM--maxWorkers=1
for jest, so it can't be that some other test tries to insert mocks at the same time as well and interfere with itjanpio
PinkiePie
04/05/2022, 10:30 AMprismagraphql/mongo-single-replica:5.0.3
container. here is my config:
name: Backend tests pipeline
on: [push]
jobs:
test_mongo_action:
runs-on: ubuntu-latest
name: Test Server/GraphQL
strategy:
matrix:
work-dir: [./lambdas]
node-version: [16.x]
steps:
- name: Checkout repo
uses: actions/checkout@v2
- name: Create mongo Docker container
run: sudo docker run --name test_mongo -d -p 27017:27017 --env MONGO_INITDB_ROOT_USERNAME=prisma --env MONGO_INITDB_ROOT_PASSWORD=prisma --env INIT_WAIT_SEC="10" prismagraphql/mongo-single-replica:5.0.3
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}
- name: Installing Node Modules
uses: bahmutov/npm-install@v1
- name: create env file
run: |
touch .env
echo ... >> .env
echo ... >> .env
echo ... >> .env
- name: Generate Prisma Client
run: yarn build:prisma
working-directory: ${{ matrix.work-dir }}
- name: Run backend tests
id: run_backend_tests
run: yarn test --silent
working-directory: ${{ matrix.work-dir }}
I will have time to create a repo no earlier than the end of this week though 😞
I realised one more thing: I use insertMockData
function from the snippet above in the tests like that:
describe('Unlogged user', () => {
beforeAll(async () => insertMockedData());
I have multiple such sections in the file. And the only first describe
fails, the rest of the describe
in the same file works fine! I tried to re-order them, and it is always like that - the first describe
always fails, and the rest always works fine. So as for now I have temporary workaround:
describe('Prisma WriteConflict', () => {
beforeAll(async () => insertMockedData().catch(() => {}));
it('workaround', () => {});
});
at the beginning of the file.
It's a mystery for me, insertMockData
cleans up the database in every describe
and all mocks have exactly the same shape, ids, and so on, why does it fail on the first run, but the same commands work fine later... At least I have a workaround for nowjanpio