Skip to content

perf(actions): skip re-sending unchanged job summaries on the run vie… - #38617

Open
bircni wants to merge 1 commit into
go-gitea:mainfrom
bircni:perf/actions-job-summaries-poll
Open

perf(actions): skip re-sending unchanged job summaries on the run vie…#38617
bircni wants to merge 1 commit into
go-gitea:mainfrom
bircni:perf/actions-job-summaries-poll

Conversation

@bircni

@bircni bircni commented Jul 24, 2026

Copy link
Copy Markdown
Member

Split out of #38518, where the review asked to keep that branch to the correctness
fixes being backported to 1.27. The change is dropped there and continues here.

The run view polls roughly every second while a run is in progress. Every poll
loaded and re-rendered each job's GITHUB_STEP_SUMMARY markdown — up to
MaxJobNumPerRun jobs of up to 1 MiB each — even when nothing had changed, so
the cost scaled with both job count and the number of people watching the run.

  • DB-side fingerprintGetActionRunJobSummariesVersion returns COUNT(*)
    plus MAX(updated) for the summaries in scope, with the same optional jobID
    scoping as ListActionRunJobSummaries. COUNT is needed alongside
    MAX(updated) because updated has 1s granularity: MAX alone misses a
    deleted row, and a step inserted in the same second as the previous one.
  • Conditional payload — the fingerprint travels both ways (jobSummariesVersion
    on the view request and response). When the client's matches, the response omits
    jobSummaries and the content load and markdown render are skipped entirely;
    when it differs, the full set is sent as before.
  • Empty never matches — an empty fingerprint means both "this run has no
    summaries" and "the client holds none yet", so it is always treated as a miss.

There is no in-process cache: the fingerprint is computed and compared per
request, so no state is shared between requests. The rendered HTML is unchanged —
only how often it is recomputed and re-sent.

…w poll

The run view polls roughly every second while a run is in progress, and every
poll loaded and re-rendered each job's GITHUB_STEP_SUMMARY markdown, up to
MaxJobNumPerRun jobs of up to 1 MiB each, even when nothing had changed.

Compute a cheap DB-side fingerprint (row count plus the newest "updated") of
the summaries in scope, send it with the response and accept the client's
current one in the request. When they match, the response omits jobSummaries
and the client keeps what it already rendered; when they differ, the full set
is sent as before. COUNT is needed alongside MAX(updated) because "updated"
has 1s granularity, so MAX alone would miss a deleted row or a step inserted
in the same second as the previous one.

An empty fingerprint never matches, since it means both "this run has no
summaries" and "the client holds none yet".

Assisted-by: Claude Code:claude-opus-4-8
@GiteaBot GiteaBot added the lgtm/need 2 This PR needs two approvals by maintainers to be considered for merging. label Jul 24, 2026
@github-actions github-actions Bot added the topic/gitea-actions related to the actions of Gitea label Jul 24, 2026
@silverwind
silverwind requested a review from Copilot July 24, 2026 21:29

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR reduces repeated DB load, markdown rendering work, and payload size in the Actions run view’s ~1s polling loop by introducing a lightweight server-side “job summaries fingerprint” and only re-sending/re-rendering GITHUB_STEP_SUMMARY content when that fingerprint changes.

Changes:

  • Add jobSummariesVersion (a summaries fingerprint) to the Actions run view request/response model.
  • Server computes and returns the fingerprint each poll, and conditionally omits jobSummaries when the client already has the same version.
  • Client preserves the previously-rendered jobSummaries when the version is unchanged and the server omits the field.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
web_src/js/modules/gitea-actions.ts Extends the ActionsRun type with jobSummariesVersion.
web_src/js/components/ActionRunView.ts Sends the client-held fingerprint; reuses prior summaries when version matches.
routers/web/repo/actions/view.go Adds request/response fields; computes fingerprint and conditionally loads/renders summaries.
models/actions/run_job_summary.go Adds DB-side fingerprint query helper for summaries.
models/actions/run_job_summary_test.go Adds unit test coverage for fingerprint behavior.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +205 to +217
var agg struct {
Count int64 `xorm:"count"`
MaxUpdated int64 `xorm:"max_updated"`
}
if _, err := sess.
Select("COUNT(*) AS count, COALESCE(MAX(updated), 0) AS max_updated").
Get(&agg); err != nil {
return "", err
}
if agg.Count == 0 {
return "", nil
}
return fmt.Sprintf("%d-%d", agg.Count, agg.MaxUpdated), nil
Comment on lines +6 to +13
import (
"testing"

"gitea.dev/models/unittest"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
Comment on lines +42 to +51
// Job scoping: adding job B changes the all-jobs fingerprint but leaves job A's untouched.
vA := version(jobA)
require.NoError(t, UpsertActionRunJobSummary(ctx, repoID, runID, attemptID, jobB, 0, JobSummaryContentTypeMarkdown, []byte("b summary")))
assert.NotEqual(t, v2, version(0))
assert.Equal(t, vA, version(jobA))

// Deleting a step changes the fingerprint.
beforeDelete := version(jobA)
require.NoError(t, DeleteActionRunJobSummary(ctx, repoID, runID, attemptID, jobA, 1))
assert.NotEqual(t, beforeDelete, version(jobA))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

lgtm/need 2 This PR needs two approvals by maintainers to be considered for merging. topic/gitea-actions related to the actions of Gitea

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants