diff options
| author | 2025-10-03 15:50:57 +0200 | |
|---|---|---|
| committer | 2025-10-03 15:50:57 +0200 | |
| commit | 57cb4fe7482962aa8e5a05874a343474d5a453e7 (patch) | |
| tree | 666a82b538674dcda0b69b64ee019d12cbab96f2 /internal/federation/dereferencing/status.go | |
| parent | [chore] update dependencies (#4468) (diff) | |
| download | gotosocial-57cb4fe7482962aa8e5a05874a343474d5a453e7.tar.xz | |
[bugfix] status refresh race condition causing double edit notifications (#4470)
# Description
fixes possible race condition of existing status being out-of-date in enrichStatus()
## Checklist
- [x] I/we have read the [GoToSocial contribution guidelines](https://codeberg.org/superseriousbusiness/gotosocial/src/branch/main/CONTRIBUTING.md).
- [x] I/we have discussed the proposed changes already, either in an issue on the repository, or in the Matrix chat.
- [x] I/we have not leveraged AI to create the proposed changes.
- [x] I/we have performed a self-review of added code.
- [x] I/we have written code that is legible and maintainable by others.
- [x] I/we have commented the added code, particularly in hard-to-understand areas.
- [ ] I/we have made any necessary changes to documentation.
- [x] I/we have added tests that cover new code.
- [x] I/we have run tests and they pass locally with the changes.
- [x] I/we have run `go fmt ./...` and `golangci-lint run`.
Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4470
Co-authored-by: kim <grufwub@gmail.com>
Co-committed-by: kim <grufwub@gmail.com>
Diffstat (limited to 'internal/federation/dereferencing/status.go')
| -rw-r--r-- | internal/federation/dereferencing/status.go | 37 |
1 files changed, 20 insertions, 17 deletions
diff --git a/internal/federation/dereferencing/status.go b/internal/federation/dereferencing/status.go index 0e86dca7c..fffaa88a6 100644 --- a/internal/federation/dereferencing/status.go +++ b/internal/federation/dereferencing/status.go @@ -277,25 +277,30 @@ func (d *Dereferencer) enrichStatusSafely( ) (*gtsmodel.Status, ap.Statusable, bool, error) { uriStr := status.URI + // Acquire per-URI deref lock, wraping unlock + // to safely defer in case of panic, while still + // performing more granular unlocks when needed. + unlock := d.state.FedLocks.Lock(uriStr) + unlock = util.DoOnce(unlock) + defer unlock() + + var err error var isNew bool // Check if this is a new status (to us). if isNew = (status.ID == ""); !isNew { - // This is an existing status, first try to populate it. This - // is required by the checks below for existing tags, media etc. - if err := d.state.DB.PopulateStatus(ctx, status); err != nil { - log.Errorf(ctx, "error populating existing status %s: %v", uriStr, err) + // We reload the existing status, just to ensure we have the + // latest version of it. e.g. another racing thread might have + // just input a change but we still have an old status copy. + // + // Note: returned status will be fully populated, required below. + status, err = d.state.DB.GetStatusByID(ctx, status.ID) + if err != nil { + return nil, nil, false, gtserror.Newf("error getting up-to-date existing status: %w", err) } } - // Acquire per-URI deref lock, wraping unlock - // to safely defer in case of panic, while still - // performing more granular unlocks when needed. - unlock := d.state.FedLocks.Lock(uriStr) - unlock = util.DoOnce(unlock) - defer unlock() - // Perform status enrichment with passed vars. latest, statusable, err := d.enrichStatus(ctx, requestUser, @@ -479,12 +484,10 @@ func (d *Dereferencer) enrichStatus( // Ensure the final parsed status URI or URL matches // the input URI we fetched (or received) it as. - matches, err := util.URIMatches(uri, - append( - ap.GetURL(statusable), // status URL(s) - ap.GetJSONLDId(statusable), // status URI - )..., - ) + matches, err := util.URIMatches(uri, append( + ap.GetURL(statusable), // status URL(s) + ap.GetJSONLDId(statusable), // status URI + )...) if err != nil { return nil, nil, gtserror.Newf( "error checking dereferenced status uri %s: %w", |
