@@ -1104,21 +1104,10 @@ func newIssue(e *xorm.Session, doer *User, opts NewIssueOptions) (err error) {
11041104 }
11051105
11061106 // Milestone and assignee validation should happen before insert actual object.
1107-
1108- // There's no good way to identify a duplicate key error in database/sql; brute force some retries
1109- dupIndexAttempts := issueMaxDupIndexAttempts
1110- for {
1111- _ , err := e .SetExpr ("`index`" , "coalesce(MAX(`index`),0)+1" ).
1112- Where ("repo_id=?" , opts .Issue .RepoID ).
1113- Insert (opts .Issue )
1114- if err == nil {
1115- break
1116- }
1117-
1118- dupIndexAttempts --
1119- if dupIndexAttempts <= 0 {
1120- return err
1121- }
1107+ if _ , err := e .SetExpr ("`index`" , "coalesce(MAX(`index`),0)+1" ).
1108+ Where ("repo_id=?" , opts .Issue .RepoID ).
1109+ Insert (opts .Issue ); err != nil {
1110+ return ErrNewIssueInsert {err }
11221111 }
11231112
11241113 inserted , err := getIssueByID (e , opts .Issue .ID )
@@ -1201,6 +1190,24 @@ func newIssue(e *xorm.Session, doer *User, opts NewIssueOptions) (err error) {
12011190
12021191// NewIssue creates new issue with labels for repository.
12031192func NewIssue (repo * Repository , issue * Issue , labelIDs []int64 , assigneeIDs []int64 , uuids []string ) (err error ) {
1193+ // Retry several times in case INSERT fails due to duplicate key for (repo_id, index); see #7887
1194+ i := 0
1195+ for {
1196+ if err = newIssueAttempt (repo , issue , labelIDs , assigneeIDs , uuids ); err == nil {
1197+ return nil
1198+ }
1199+ if ! IsErrNewIssueInsert (err ) {
1200+ return err
1201+ }
1202+ if i ++ ; i == issueMaxDupIndexAttempts {
1203+ break
1204+ }
1205+ log .Error ("NewIssue: error attempting to insert the new issue; will retry. Original error: %v" , err )
1206+ }
1207+ return fmt .Errorf ("NewIssue: too many errors attempting to insert the new issue. Last error was: %v" , err )
1208+ }
1209+
1210+ func newIssueAttempt (repo * Repository , issue * Issue , labelIDs []int64 , assigneeIDs []int64 , uuids []string ) (err error ) {
12041211 sess := x .NewSession ()
12051212 defer sess .Close ()
12061213 if err = sess .Begin (); err != nil {
@@ -1214,7 +1221,7 @@ func NewIssue(repo *Repository, issue *Issue, labelIDs []int64, assigneeIDs []in
12141221 Attachments : uuids ,
12151222 AssigneeIDs : assigneeIDs ,
12161223 }); err != nil {
1217- if IsErrUserDoesNotHaveAccessToRepo (err ) {
1224+ if IsErrUserDoesNotHaveAccessToRepo (err ) || IsErrNewIssueInsert ( err ) {
12181225 return err
12191226 }
12201227 return fmt .Errorf ("newIssue: %v" , err )
@@ -1223,7 +1230,6 @@ func NewIssue(repo *Repository, issue *Issue, labelIDs []int64, assigneeIDs []in
12231230 if err = sess .Commit (); err != nil {
12241231 return fmt .Errorf ("Commit: %v" , err )
12251232 }
1226- sess .Close ()
12271233
12281234 return nil
12291235}
0 commit comments