Variable scopes in a ScriptRunner custom rest endpoint

Introduction

Here is something I wanted to share because I could not fine any examples or documentation about.

I have a big and complex custom rest endpoint script in ScriptRunner for Jira Data Center that's being used to import data from another system into Jira.

The issue

The script works really well until I start running those imports in parallel.
What I noticed: when importing 2 items at the same time some things get mixed up. Items are created with the issuetype of the other item or even in the target project of the other item.
I ended up with issues from a type that was not even included in the issue type scheme of that project.

My mistake was to use global variables  for the issue type and project in the script. I declared the variables outside of the rest method and provided a value inside the method. The values of those variables were "remembered" by the system and used when another request ran at the same time.

Example with issue

Here is an example script to reproduce the issue:

import com.onresolve.scriptrunner.runner.rest.common.CustomEndpointDelegate
import groovy.transform.BaseScript
import javax.ws.rs.core.MultivaluedMap
import groovy.json.JsonBuilder
import groovy.transform.Field
import javax.ws.rs.core.Response

@Field String myNumber

@BaseScript CustomEndpointDelegate delegate


testParallel( httpMethod: "GET", groups: ["jira-administrators"] ) {
    MultivaluedMap queryParams, String body -> 
    myNumber = queryParams.getFirst("myNumber") as String
    return Response.ok(new JsonBuilder([number: myNumber]).toString()).build() 
}

testParallelWait( httpMethod: "GET", groups: ["jira-administrators"] ) {
    MultivaluedMap queryParams, String body ->
    myNumber = queryParams.getFirst("myNumber") as String
    sleep(10000)
    return Response.ok(new JsonBuilder([number: myNumber]).toString()).build() 
}

myNumber is declared gloablly and gets a value in the actual methods.

  1. Call this url and do not wait for it to reply
    https://<jira-url>/rest/scriptrunner/latest/custom/testParallelWait?myNumber=7

  2. Call this url
    https://<jira-url>/rest/scriptrunner/latest/custom/testParallel?myNumber=3

  3. The first call will reply with 3 and not with 7
    --> when 1 run is already executing and another one alters a global variable during that time the 1st run will use the new value

Example without issue

Here is how to properly define the variable:

import com.onresolve.scriptrunner.runner.rest.common.CustomEndpointDelegate
import groovy.transform.BaseScript
import javax.ws.rs.core.MultivaluedMap
import groovy.json.JsonBuilder
import groovy.transform.Field
import javax.ws.rs.core.Response

@BaseScript CustomEndpointDelegate delegate


testParallel( httpMethod: "GET", groups: ["jira-administrators"] ) { MultivaluedMap queryParams, String body -> 
    String myNumber
    myNumber = queryParams.getFirst("myNumber") as String
    myNumber = getNumber(myNumber)
    return Response.ok(new JsonBuilder([number: myNumber]).toString()).build() 
}

testParallelWait( httpMethod: "GET", groups: ["jira-administrators"] ) { MultivaluedMap queryParams, String body ->
    String myNumber
    myNumber = queryParams.getFirst("myNumber") as String
    myNumber = getNumber(myNumber)
    sleep(10000)
    return Response.ok(new JsonBuilder([number: myNumber]).toString()).build() 
}

def getNumber(String myNumber){
    return "Hello ${myNumber}"
}

myNumber is declared locally in the methods.
Additionally I'm using the getNumber method where the return value is being prefixed with "Hello" to really show how the variable is not being altered by other calls to the endpoint.

Conclusion

When writing scripts we sometimes neglect the rules of coding. Thinks about your variable scopes carefully!

I hope this articles will help someone one day that struggled with this just like me.
If anyone can share the technical side of the JVM and threads related to this that would be very welcome as addition.

 

REST Endpoint documentation from Adaptavist can be found here.

1 comment

Comment

Log in or Sign up to comment
Matt Doar _Adaptavist_
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
February 7, 2025

Thanks for the reminder! If you'd like us to add some cautionary text about global variables to the docs, please would you create a support ticket at https://www.scriptrunnerhq.com/help/support with a link to this handy post.

TAGS
AUG Leaders

Atlassian Community Events