fix(backend) : add validation constraints and fix concurrent numbering
- Add Assert\Choice on ClientTicket type and status with typed constants - Add Assert\Url on GiteaConfiguration, BookStackConfiguration, TaskBookStackLink, ClientTicket - Fix concurrent task/ticket numbering: use pg_advisory_xact_lock instead of FOR UPDATE with MAX() - Wrap CreateTaskTool numbering in transaction - Harmonize repository contracts: both return max number, caller adds +1 Tickets: T-004, T-008, T-011, T-012 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -20,13 +20,20 @@ class TaskRepository extends ServiceEntityRepository
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the max task number for a project, using a row-level lock
|
||||
* Returns the max task number for a project, using an advisory lock
|
||||
* to prevent race conditions when creating tasks concurrently.
|
||||
*/
|
||||
public function findMaxNumberByProjectForUpdate(Project $project): int
|
||||
{
|
||||
$conn = $this->getEntityManager()->getConnection();
|
||||
|
||||
// Use PostgreSQL advisory lock (project ID as lock key) instead of FOR UPDATE
|
||||
// because FOR UPDATE is not allowed with aggregate functions in PostgreSQL.
|
||||
$conn->executeStatement(
|
||||
'SELECT pg_advisory_xact_lock(:project)',
|
||||
['project' => $project->getId()],
|
||||
);
|
||||
|
||||
$result = $conn->fetchOne(
|
||||
'SELECT COALESCE(MAX(number), 0) FROM task WHERE project_id = :project',
|
||||
['project' => $project->getId()],
|
||||
|
||||
Reference in New Issue
Block a user