[performance] handle emoji refreshes asynchronously when fetched as part of account|status dereferences (#4486)

# Description

Updates our dereferencer emoji handling to work asynchronously when going through the route of account or status dereferencing.

closes https://codeberg.org/superseriousbusiness/gotosocial/issues/4485

## 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.
- [ ] I/we have commented the added code, particularly in hard-to-understand areas.
- [ ] I/we have made any necessary changes to documentation.
- [ ] I/we have added tests that cover new code.
- [ ] 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/4486
Co-authored-by: kim <grufwub@gmail.com>
Co-committed-by: kim <grufwub@gmail.com>
This commit is contained in:
kim 2025-10-08 14:13:40 +02:00 committed by tobi
commit 5fd52369c9
5 changed files with 62 additions and 21 deletions

View file

@ -44,11 +44,6 @@ type ProcessingEmoji struct {
mgr *Manager // mgr instance (access to db / storage)
}
// ID returns the ID of the underlying emoji.
func (p *ProcessingEmoji) ID() string {
return p.emoji.ID // immutable, safe outside mutex.
}
// LoadEmoji blocks until the static and fullsize image has been processed, and then returns the completed emoji.
func (p *ProcessingEmoji) Load(ctx context.Context) (*gtsmodel.Emoji, error) {
emoji, done, err := p.load(ctx)
@ -63,6 +58,33 @@ func (p *ProcessingEmoji) Load(ctx context.Context) (*gtsmodel.Emoji, error) {
return emoji, err
}
func (p *ProcessingEmoji) LoadAsync(deferred func()) *gtsmodel.Emoji {
p.mgr.state.Workers.Dereference.Queue.Push(func(ctx context.Context) {
if deferred != nil {
defer deferred()
}
if _, _, err := p.load(ctx); err != nil {
log.Errorf(ctx, "error loading emoji: %v", err)
}
})
// Placeholder returns a copy of internally stored processing placeholder,
// returning only the fields that may be known *before* completion,
// and as such all fields which are safe to concurrently read.
placeholder := new(gtsmodel.Emoji)
placeholder.ID = p.emoji.ID
placeholder.Shortcode = p.emoji.Shortcode
placeholder.Domain = p.emoji.Domain
placeholder.Cached = new(bool)
placeholder.ImageRemoteURL = p.emoji.ImageRemoteURL
placeholder.ImageStaticRemoteURL = p.emoji.ImageStaticRemoteURL
placeholder.Disabled = p.emoji.Disabled
placeholder.VisibleInPicker = p.emoji.VisibleInPicker
placeholder.CategoryID = p.emoji.CategoryID
return placeholder
}
// load is the package private form of load() that is wrapped to catch context canceled.
func (p *ProcessingEmoji) load(ctx context.Context) (
emoji *gtsmodel.Emoji,