Log system notes that fail to persist
What does this MR do and why?
SystemNotes::BaseService#create_note calls Note.create and discards the return
value, and no caller checks it either. A system note that fails to save therefore
disappears with no log line, no exception, and no metric.
That silence is currently blocking the investigation into intermittently missing
"added N commits" notes. On a confirmed production case we can show that the job
completed successfully, that no exception was raised, and — from the job's
db_main_write_count — that no INSERT was issued. Nothing records why the save
was abandoned.
This MR logs that failure. It is observability only: the unpersisted note is still returned and callers behave exactly as before.
The payload distinguishes the two ways a save can fail without raising:
note_errors |
Meaning |
|---|---|
| populated | a validation rejected the record |
| empty | a callback halted the save |
It also carries noteable_type, noteable_id, note_action, and note_bytesize,
so a failure can be tied back to a specific noteable and to the size of the body
being rendered.
Log volume is negligible: the line is only emitted when a note fails to persist.
Why not Note.create!
Raising here would be a much larger change than it looks. create_note is shared by
every system-note service, and in MergeRequests::RefreshService an exception from
notify_about_push aborts the rest of the loop and skips execute_async_workers —
which is what enqueues MergeRequests::Refresh::PipelineWorker,
WebHooksWorker, and (EE) ApprovalWorker. A missing system note would become a
missing CI pipeline. UpdateMergeRequestsWorker is also explicitly not idempotent,
so the retries would re-run diff reloading.
Logging first tells us the failure rate and the cause before we decide what the fix should be.
References
How to set up and validate locally
bundle exec rspec spec/services/system_notes/base_service_spec.rbTo see the log line, stub a failing save in a Rails console:
project = Project.first
issue = project.issues.first
author = project.first_owner
summary = NoteSummary.new(issue, project, author, 'added 1 commit', action: 'commit')
allow(Note).to receive(:create).and_return(Note.new) # or make the record invalid
SystemNotes::BaseService.new(noteable: issue, container: project, author: author)
.send(:create_note, summary)MR acceptance checklist
Evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.