@@ -1104,21 +1104,10 @@ func newIssue(e *xorm.Session, doer *User, opts NewIssueOptions) (err error) {
1104
1104
}
1105
1105
1106
1106
// 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 }
1122
1111
}
1123
1112
1124
1113
inserted , err := getIssueByID (e , opts .Issue .ID )
@@ -1201,6 +1190,24 @@ func newIssue(e *xorm.Session, doer *User, opts NewIssueOptions) (err error) {
1201
1190
1202
1191
// NewIssue creates new issue with labels for repository.
1203
1192
func 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 ) {
1204
1211
sess := x .NewSession ()
1205
1212
defer sess .Close ()
1206
1213
if err = sess .Begin (); err != nil {
@@ -1214,7 +1221,7 @@ func NewIssue(repo *Repository, issue *Issue, labelIDs []int64, assigneeIDs []in
1214
1221
Attachments : uuids ,
1215
1222
AssigneeIDs : assigneeIDs ,
1216
1223
}); err != nil {
1217
- if IsErrUserDoesNotHaveAccessToRepo (err ) {
1224
+ if IsErrUserDoesNotHaveAccessToRepo (err ) || IsErrNewIssueInsert ( err ) {
1218
1225
return err
1219
1226
}
1220
1227
return fmt .Errorf ("newIssue: %v" , err )
@@ -1223,7 +1230,6 @@ func NewIssue(repo *Repository, issue *Issue, labelIDs []int64, assigneeIDs []in
1223
1230
if err = sess .Commit (); err != nil {
1224
1231
return fmt .Errorf ("Commit: %v" , err )
1225
1232
}
1226
- sess .Close ()
1227
1233
1228
1234
return nil
1229
1235
}
0 commit comments