Uploaded image for project: 'Jenkins'
  1. Jenkins
  2. JENKINS-72920

Retry after restart causes IllegalStateException: ID spotbugs is already used by another action: io.jenkins.plugins.analysis.core.model.ResultAction for SpotBugs

      With a Jenkinsfile using an idiom retrying a node block after a controller or agent failure,
      and the content of the node block including usage of

      recordIssues(tool: spotBugs(), qualityGates: [[threshold: 1, type: 'TOTAL', unstable: true]])

      then the build fails after restart with the following stacktrace

      java.lang.IllegalStateException: ID spotbugs is already used by another action: io.jenkins.plugins.analysis.core.model.ResultAction for SpotBugs
      
      	at io.jenkins.plugins.analysis.core.steps.IssuesPublisher.ensureThatIdIsUnique(IssuesPublisher.java:147)
      	at io.jenkins.plugins.analysis.core.steps.IssuesPublisher.attachAction(IssuesPublisher.java:97)
      	at io.jenkins.plugins.analysis.core.steps.IssuesRecorder.publishResult(IssuesRecorder.java:879)
      	at io.jenkins.plugins.analysis.core.steps.IssuesRecorder.record(IssuesRecorder.java:798)
      	at io.jenkins.plugins.analysis.core.steps.IssuesRecorder.perform(IssuesRecorder.java:760)
      	at io.jenkins.plugins.analysis.core.steps.RecordIssuesStep$Execution.run(RecordIssuesStep.java:1176)
      	at io.jenkins.plugins.analysis.core.steps.RecordIssuesStep$Execution.run(RecordIssuesStep.java:1131)
      

      The proper behaviour should be to overwrite the existing report with a warning.

          [JENKINS-72920] Retry after restart causes IllegalStateException: ID spotbugs is already used by another action: io.jenkins.plugins.analysis.core.model.ResultAction for SpotBugs

          Ulli Hafner added a comment -

          Actually this behavior is intended to avoid that people use the same ID twice and overwrite their results.

          Shouldn't Jenkins core provide a kind of transactional control that prevents such problems for plugins? It makes no sense to restart a step that already published the results.

          Ulli Hafner added a comment - Actually this behavior is intended to avoid that people use the same ID twice and overwrite their results. Shouldn't Jenkins core provide a kind of transactional control that prevents such problems for plugins? It makes no sense to restart a step that already published the results.

          Jesse Glick added a comment -

          this behavior is intended

          The intention was fine but it needs to be relaxed to support this situation.

          a kind of transactional control

          Without a database? Nothing in Jenkins is atomic.

          It makes no sense to restart a step that already published the results.

          It does, because the whole stage (or whatever block includes agent provisioning, source code checkout, build, and publishing) is retried when there is an infrastructure failure. In most cases the failure occurs earlier before recordIssues runs, but when multiple publishing-type steps are run it can happen that the agent fails after recordIssues has been run but while other steps are running. When the block is restarted, we expect everything to run again.

          (At least for continuous integration and similar projects. If your project definition includes some sort of step which is inherently not idempotent, like deploying an artifact to a system which cannot handle repeated uploads, then you would just not be able to opt in to this retry system.)

          Jesse Glick added a comment - this behavior is intended The intention was fine but it needs to be relaxed to support this situation. a kind of transactional control Without a database? Nothing in Jenkins is atomic. It makes no sense to restart a step that already published the results. It does, because the whole stage (or whatever block includes agent provisioning, source code checkout, build, and publishing) is retried when there is an infrastructure failure. In most cases the failure occurs earlier before recordIssues runs, but when multiple publishing-type steps are run it can happen that the agent fails after recordIssues has been run but while other steps are running. When the block is restarted, we expect everything to run again. (At least for continuous integration and similar projects. If your project definition includes some sort of step which is inherently not idempotent, like deploying an artifact to a system which cannot handle repeated uploads, then you would just not be able to opt in to this retry system.)

          Jesse Glick added a comment -

          Jesse Glick added a comment - This issue was reported based on an incident on CloudBees servers, but ci.jenkins.io includes very similar logic for every plugin build. See https://github.com/jenkins-infra/pipeline-library/blob/9d9f45f6f142e4cef15340a3a6c638eadb843da0/vars/buildPlugin.groovy#L64-L65 vs. https://github.com/jenkins-infra/pipeline-library/blob/9d9f45f6f142e4cef15340a3a6c638eadb843da0/vars/buildPlugin.groovy#L181-L279

          Ulli Hafner added a comment -

          The intention was fine but it needs to be relaxed to support this situation.

          Is this restart information available as a flag or property?

          How do other plugins handle this problem? The coverage plugin will publish another action with the same ID, seems that I forgot to add the assertion there as well. What about plugins that allow aggregations? Do they work correctly if some parts of the aggregation are already stored.

          Ulli Hafner added a comment - The intention was fine but it needs to be relaxed to support this situation. Is this restart information available as a flag or property? How do other plugins handle this problem? The coverage plugin will publish another action with the same ID, seems that I forgot to add the assertion there as well. What about plugins that allow aggregations? Do they work correctly if some parts of the aggregation are already stored.

          Jesse Glick added a comment -

          Is this restart information available as a flag or property?

          No. I suppose you could walk the flow graph up to find a retry block, assuming that is what the pipeline is using (but it could just be a Groovy loop of some sort).

          How do other plugins handle this problem?

          By not throwing an error I guess. junit does not seem to be bothered. (It does support discriminating reports by stage name but I think that is orthogonal.)

          Jesse Glick added a comment - Is this restart information available as a flag or property? No. I suppose you could walk the flow graph up to find a retry block, assuming that is what the pipeline is using (but it could just be a Groovy loop of some sort). How do other plugins handle this problem? By not throwing an error I guess. junit does not seem to be bothered. (It does support discriminating reports by stage name but I think that is orthogonal.)

            Unassigned Unassigned
            vlatombe Vincent Latombe
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

              Created:
              Updated: