-
-
Notifications
You must be signed in to change notification settings - Fork 251
Fix SQLite deadlock with recurring tasks #1053
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 2 commits
04f8754
40c85db
ec20769
8ace5c7
c9d168c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -721,33 +721,33 @@ func (r *AttachmentRepo) CreateMissingThumbnails(ctx context.Context, groupId uu | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| log.Err(err).Msg("failed to open pubsub topic") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| count := 0 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if !r.thumbnail.Enabled { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return 0, nil | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| var messages []*pubsub.Message | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for _, attachment := range attachments { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if r.thumbnail.Enabled { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if !attachment.QueryThumbnail().ExistX(ctx) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if count > 0 && count%100 == 0 { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| time.Sleep(2 * time.Second) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| err = topic.Send(ctx, &pubsub.Message{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Body: []byte(fmt.Sprintf("attachment_created:%s", attachment.ID.String())), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Metadata: map[string]string{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "group_id": groupId.String(), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "attachment_id": attachment.ID.String(), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "title": attachment.Title, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "path": attachment.Path, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if err != nil { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| log.Err(err).Msg("failed to send message to topic") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| continue | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| count++ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if !attachment.QueryThumbnail().ExistX(ctx) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| msg := &pubsub.Message{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Body: fmt.Appendf(nil, "attachment_created:%s", attachment.ID.String()), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Metadata: map[string]string{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "group_id": groupId.String(), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "attachment_id": attachment.ID.String(), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "title": attachment.Title, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "path": attachment.Path, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| messages = append(messages, msg) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+644
to
+655
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Avoid Ent’s ExistX (panics on error); handle existence check errors ExistX will panic on DB errors. Use Exist(ctx) and handle err. - if !attachment.QueryThumbnail().ExistX(ctx) {
+ exists, err := attachment.QueryThumbnail().Exist(ctx)
+ if err != nil {
+ log.Err(err).
+ Str("group_id", groupId.String()).
+ Str("attachment_id", attachment.ID.String()).
+ Msg("failed to check thumbnail existence")
+ return 0, err
+ }
+ if !exists {
msg := &pubsub.Message{
Body: fmt.Appendf(nil, "attachment_created:%s", attachment.ID.String()),
Metadata: map[string]string{
"group_id": groupId.String(),
"attachment_id": attachment.ID.String(),
"title": attachment.Title,
"path": attachment.Path,
},
}
messages = append(messages, msg)
}📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for _, msg := range messages { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| err = topic.Send(ctx, msg) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if err != nil { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| log.Err(err).Msg("failed to send 'attachment_created' message to topic 'thumbnails'") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return count, nil | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return len(messages), nil | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+642
to
+664
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Major: Silent message loss on send failures. The current implementation collects messages in a slice and sends them individually (line 744). When Consider one of these approaches:
Apply this diff to fail fast on send errors: for _, msg := range messages {
err = topic.Send(ctx, msg)
if err != nil {
log.Err(err).Msg("failed to send 'attachment_created' message to topic 'thumbnails'")
+ return 0, fmt.Errorf("failed to send message to thumbnails topic: %w", err)
}
}
return len(messages), nilAlternatively, to aggregate errors and return partial success count: + sent := 0
for _, msg := range messages {
err = topic.Send(ctx, msg)
if err != nil {
log.Err(err).Msg("failed to send 'attachment_created' message to topic 'thumbnails'")
+ } else {
+ sent++
}
}
- return len(messages), nil
+ if sent < len(messages) {
+ return sent, fmt.Errorf("failed to send %d of %d messages", len(messages)-sent, len(messages))
+ }
+ return sent, nil🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| func (r *AttachmentRepo) UploadFile(ctx context.Context, itemGroup *ent.Group, doc ItemCreateAttachment) (string, error) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -861,6 +861,7 @@ func (r *AttachmentRepo) processThumbnailFromImage(ctx context.Context, groupId | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| log.Debug().Msg("uploading thumbnail file") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Get the group for uploading the thumbnail | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| log.Debug().Msg(fmt.Sprintf("OpenConnections = %d", r.db.Debug().Sql().Stats().OpenConnections)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| group, err := r.db.Group.Get(ctx, groupId) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Compile-time issue: invalid call chain to DB stats ent.Client doesn’t expose Sql(); use DB() to access database/sql stats. - log.Debug().Msg(fmt.Sprintf("OpenConnections = %d", r.db.Debug().Sql().Stats().OpenConnections))
+ log.Debug().Int("open_connections", r.db.DB().Stats().OpenConnections).Msg("DB stats")📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if err != nil { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return "", err | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion | 🟠 Major
Move the thumbnail enabled check before pubsub setup.
The early return for disabled thumbnails (lines 638-640) occurs after establishing the pubsub connection (lines 629-636). This wastes resources by opening a topic that won't be used.
Apply this diff to check the flag first:
if err != nil { return 0, err } - pubsubString, err := utils.GenerateSubPubConn(r.pubSubConn, "thumbnails") - if err != nil { - log.Err(err).Msg("failed to generate pubsub connection string") - } - topic, err := pubsub.OpenTopic(ctx, pubsubString) - if err != nil { - log.Err(err).Msg("failed to open pubsub topic") - } - if !r.thumbnail.Enabled { return 0, nil } + pubsubString, err := utils.GenerateSubPubConn(r.pubSubConn, "thumbnails") + if err != nil { + log.Err(err).Msg("failed to generate pubsub connection string") + return 0, err + } + topic, err := pubsub.OpenTopic(ctx, pubsubString) + if err != nil { + log.Err(err).Msg("failed to open pubsub topic") + return 0, err + } + var messages []*pubsub.Message📝 Committable suggestion
🤖 Prompt for AI Agents