Skip to content

Support Actions concurrency syntax #32751

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

Draft
wants to merge 19 commits into
base: main
Choose a base branch
from

Conversation

Zettat123
Copy link
Contributor

@Zettat123 Zettat123 commented Dec 7, 2024

Fix #24769
Fix #32662
Fix #33260

Depends on https://gitea.com/gitea/act/pulls/124

⚠️ BREAKING ⚠️

This PR removes the auto-cancellation feature added by #25716. Users need to manually add concurrency to workflows to control concurrent workflows or jobs.

@GiteaBot GiteaBot added the lgtm/need 2 This PR needs two approvals by maintainers to be considered for merging. label Dec 7, 2024
@github-actions github-actions bot added modifies/api This PR adds API routes or modifies them modifies/go Pull requests that update Go code modifies/migrations modifies/dependencies labels Dec 7, 2024
@Zettat123 Zettat123 force-pushed the support-actions-concurrency branch from 3551677 to fcf4517 Compare December 10, 2024 08:56
@lunny lunny added this to the 1.24.0 milestone Dec 16, 2024
@Zettat123 Zettat123 force-pushed the support-actions-concurrency branch from 52833e7 to 130f2a2 Compare December 17, 2024 01:49
@Zettat123 Zettat123 force-pushed the support-actions-concurrency branch 3 times, most recently from 461c7c1 to d5168a2 Compare January 6, 2025 06:16
@Zettat123 Zettat123 force-pushed the support-actions-concurrency branch from e038ed2 to f77f266 Compare January 10, 2025 06:00
@Zettat123 Zettat123 changed the title WIP: Support concurrency for Actions WIP: Support Actions concurrency syntax Jan 15, 2025
@Zettat123 Zettat123 force-pushed the support-actions-concurrency branch from ad71599 to 8f5948b Compare January 15, 2025 03:03
@Zettat123

This comment was marked as resolved.

wxiaoguang added a commit that referenced this pull request Jan 15, 2025
)

Move the main logic of `generateTaskContext` and `findTaskNeeds` to the
`services` layer.

This is a part of #32751, since we need the git context and `needs` to
parse the concurrency expressions.

---------

Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
@wxiaoguang
Copy link
Contributor

If you'd like to work with others' PRs often, maybe you can ask @go-gitea/technical-oversight-committee or some core members like @lunny to apply a merger's access, then you can edit PRs directly

@ChristopherHX
Copy link
Contributor

I would expect this to happen < 5 times per year. I actually only applied as maintainer due to work with others' PRs. I will ask formally in discord.

@ChristopherHX
Copy link
Contributor

New Defect found, needs fixing in gitea/act

invalid jobs: yaml: unmarshal errors:\n  line 4: cannot unmarshal !!str `test` into model.RawConcurrency

workflow

on: push
jobs:
  test:
    concurrency: test
    runs-on: ubuntu-latest
    steps:
    - name: Checkout code
      uses: actions/checkout@v4

short syntax not parseable.

Do we have this bug in act_runner as well? Do we have this bug in Gitea already?

@Naxdy
Copy link
Contributor

Naxdy commented Jul 18, 2025

One thing that I've noticed while running it is that manually cancelling a job that is blocking another job will not start the blocked job. You have to manually cancel & re-run the blocked job for it to be picked up.

So, if e.g. you have a job with:

concurrency:
  group: main
  cancel-in-progress: false

And you push twice to main, then cancel the job that was created first, the second job will never start.

@ChristopherHX ChristopherHX marked this pull request as draft July 18, 2025 13:41
@ChristopherHX
Copy link
Contributor

Thanks for pointing this out, I convert is to a draft until I am certain this works correctly.

I will add this scenario to the test cases and try to fix this

@Naxdy
Copy link
Contributor

Naxdy commented Jul 18, 2025

Sounds good. Feel free to ping / DM on discord if you want me to test something, or need something else. I've been running this for a while on my instance already.

@Zettat123
Copy link
Contributor Author

@ChristopherHX Sorry for the late reply, as I was busy with other work last month. Thank you for the improvements and bug fixes to this PR. Please feel free to update the code. I will also check if there are still issues with this PR.

@ChristopherHX
Copy link
Contributor

Hi,

No problem, once we both agree this is finished and can be merged I approve.

Good that you already looked at the cancellation problem.

I still think about if my code removal is correct or not in sense of not only let existing tests pass.

I had another behavior difference
If we do not have cancel in progress

  • GitHub Actions cancells all earlier blocked runs/jobs (only inprogress are kept if cancel-in-progress is false)
  • This PR queues up and runs every Run one by one

Would we want to add a custom boolean to implement both behaviors?

concurrency:
  cancel-pending: true # default true for GitHub Actions Compat, false for current implementation

Would we want to keep the behavior difference and document it?

if err != nil {
ctx.ServerError("GetRunByIndex", err)
}
if err := actions_service.EmitJobsIfReady(run.ID); err != nil {
Copy link
Contributor

Choose a reason for hiding this comment

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

Queue EmitJobsIfReady from Actions Notifier Job and Workflow Completed?

(The event source used by workflow_run and workflow_job webhooks / action trigger)

I mean whatif the job is cancelled by abandoning or other reasons.

Less explicit code that has the same weakness towards all ways of cancellation

Copy link
Contributor Author

Choose a reason for hiding this comment

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

When a job completes (regardless of its status being successful, failed or cancelled), we need to check for other jobs that might have been blocked by it. I add the cancelled job to the queue so that the blocked jobs can be detected.

I mean whatif the job is cancelled by abandoning or other reasons.

Yes, this change cannot cover all cases where jobs are cancelled. So I am thinking that if we can do this check when a job reaches its final status (Success, Failed, Cancelled, and Skipped). Maybe we can move UpdateRunJob to services layer to allow it to call EmitJobsIfReady when a job's status is updated.

@Zettat123
Copy link
Contributor Author

I still think about if my code removal is correct or not in sense of not only let existing tests pass.

I think these changes look good. Thanks for simplifying the code.

I had another behavior difference If we do not have cancel in progress

  • GitHub Actions cancells all earlier blocked runs/jobs (only inprogress are kept if cancel-in-progress is false)
  • This PR queues up and runs every Run one by one

Yes. I noticed the behavior difference between GitHub actions and my implementation. I think for now we can use GitHub's logic. And in the future, we can add the cancel-pending option as a new feature. If we agree to this solution, I would like to modify the current logic (or you can push your changes if you have done :) ).

Comment on lines 39 to 43
RawConcurrencyGroup string // raw concurrency.group
RawConcurrencyCancel string // raw concurrency.cancel-in-progress
IsConcurrencyEvaluated bool // whether RawConcurrencyGroup have been evaluated, only valid when RawConcurrencyGroup is not empty
ConcurrencyGroup string `xorm:"index"` // evaluated concurrency.group
ConcurrencyCancel bool // evaluated concurrency.cancel-in-progress
Copy link
Contributor

Choose a reason for hiding this comment

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

  1. Are there some examples about how RawConcurrencyGroup vs ConcurrencyGroup works?
  2. Does the xorm:"index" have effect? For example: are there SQLs like WHERE concurrency_group=... without other index? Or should the index be optimized like (repo_id, concurrency_group)?

Copy link
Contributor

@ChristopherHX ChristopherHX Jul 20, 2025

Choose a reason for hiding this comment

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

About the first, while not an example...

  • RawConcurrencyGroup stores something like ${{ github.run_id }}, e.g. once job dependencies are ready / before the job is queued this is going to be evaluated
    • this field is not used to cancel / block any jobs/workflows
    • avoid parsing the workflow again
  • While ConcurrencyGroup stores the expression result and is used for concurrency processing
    • Used in calculate Concurrency Blocked / to find jobs/workflows to cancel that has state running/queued

In my Opinion we might need this for the ActionRun table as well, once we rerun the workflow/job variables in ${{ vars.MY_VAR }} might be updated.

I keep the point 2 unanswered, because I need to understand this as well. repo_id in the index sounds reasonable but could also be not specific enough.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

For question 2, since the scope of concurrency_group is the repo, we always use repo_id when querying with concurrency_group. So we can use combined index here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
lgtm/need 1 This PR needs approval from one additional maintainer to be merged. modifies/go Pull requests that update Go code modifies/migrations pr/breaking Merging this PR means builds will break. Needs a description what exactly breaks, and how to fix it!
Projects
None yet
Development

Successfully merging this pull request may close these issues.

workflow_dispatch allows only one job in a branch [Actions] Opt-out from auto-cancellation [Actions] Support concurrency syntax
8 participants