Skip to content

Commit

Permalink
issue 879: add composite index constraint to block concurrent inserts…
Browse files Browse the repository at this point in the history
… of the same item to actions table
  • Loading branch information
dwerner committed May 1, 2024
1 parent 4a15b37 commit 9c8aaee
Show file tree
Hide file tree
Showing 4 changed files with 73 additions and 10 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -119,3 +119,4 @@ yalc.lock
# IDE
.idea/
.envrc
.vscode
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { Logger } from '@graphprotocol/common-ts'
import { QueryInterface } from 'sequelize'

interface MigrationContext {
queryInterface: QueryInterface
logger: Logger
}

interface Context {
context: MigrationContext
}

export async function up({ context }: Context): Promise<void> {
const { queryInterface, logger } = context

logger.info('Adding composite unique constraint to Actions table')
// Add the new composite primary key
await queryInterface.addConstraint('Actions', {
fields: ['deploymentID', 'source'],
type: 'unique',
name: 'Actions_ckey_unique_deploymentID_source',
})
}

export async function down({ context }: Context): Promise<void> {
const { queryInterface, logger } = context
logger.info('Removing composite uniqie constraint from Actions table')
await queryInterface.removeConstraint(
'Actions',
'Actions_ckey_unique_deploymentID_source',
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import {
OrderDirection,
QueryFeeModels,
} from '@graphprotocol/indexer-common'
import { CombinedError } from '@urql/core'
import { CombinedError, OperationResult } from '@urql/core'
import { GraphQLError } from 'graphql'
import {
createTestManagementClient,
Expand Down Expand Up @@ -532,28 +532,51 @@ describe('Actions', () => {
.toPromise(),
).resolves.toHaveProperty('data.actions', [])
})

test('Rejects duplicate queued actions', async () => {

test('Rejects duplicate actions', async function rejectsDuplicateActions() {
console.log('running Rejects duplicate actions test')
class ResultWrapper {
constructor(
public actionNum: number,
public inner: OperationResult<Action>,
) {}
}
const inputAction = queuedAllocateAction
const mutations: Promise<any>[] = []
for (let i = 0; i < 50; i++) {
mutations.push(client.mutation(QUEUE_ACTIONS_MUTATION, { actions: [inputAction] }).toPromise())
const mutations: Promise<ResultWrapper>[] = []
for (let i = 0; i < 5; i++) {
mutations.push(
(async function pushMutation() {
return new ResultWrapper(
i,
await client
.mutation(QUEUE_ACTIONS_MUTATION, { actions: [inputAction] })
.toPromise(),
)
})(),
)
}

const results = await Promise.all(mutations)
for (const result of results) {
expect(result.data).not.toBeNull()
for (const actionResult of results) {
expect(actionResult).not.toBeNull()
if (actionResult.inner.data === null) {
expect(actionResult.inner.error).not.toBeNull()
console.log(
`action ${actionResult.actionNum} result.error:`,
actionResult.inner.error,
)
} else {
expect(actionResult.inner.data).not.toBeNull()
}
}

const actions = await client
.query(ACTIONS_QUERY, { filter: { type: ActionType.ALLOCATE } })
.toPromise()

expect(actions.data.actions).toHaveLength(1)
console.log('actions.data.actions', actions.data.actions)
})


test('Reject duplicate queued action from different source', async () => {
const inputAction = queuedAllocateAction
const expected = await actionInputToExpected(inputAction, 1)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,13 @@ export const defineActionModels = (sequelize: Sequelize): ActionModels => {
{
modelName: 'Action',
sequelize,
indexes: [
{
fields: ['deploymentID', 'source'],
unique: true,
name: 'Actions_ckey_unique_deploymentID_source',
},
],
validate: {
requiredActionParams() {
switch (this.type) {
Expand Down

0 comments on commit 9c8aaee

Please sign in to comment.