Forums

Articles
Create
cancel
Showing results for 
Search instead for 
Did you mean: 

Limit the impact of an expensive scripted field (script runner)

Jens Kisters __SeibertSolutions
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.
September 8, 2020

Hi everyone,

due to the lack of a documented Tempo Timesheets Java API i have created a script runner scripted field that sums up the Tempo field "Billed Time" for an issue using the Tempo Rest API.

This script runs over 100ms when the field is rendered.

This sounds to me like it has the potential for a heavy performance impact.

So i removed it's searcher, restricted the field to a more narrow context and kept it out of any screens.

But the business use case doesnt allow to narrow down the context very far this still feels insufficient,

i can for example see the field is rendered when an app finds a corresponding issue in /rest/api/2/search or someone comments an issue.

Does anyone have a creative idea to restrict the performance impact any further?

How did you guys solve similar problems?

Cheers

Jens

 

4 answers

2 accepted

1 vote
Answer accepted
Alexander Eck [Tempo]
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.
September 9, 2020

Hi Jens,

I am not an expert in Scriptrunner but maybe you can use something in this direction:

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.worklog.Worklog
import com.onresolve.scriptrunner.runner.customisers.PluginModule
import com.onresolve.scriptrunner.runner.customisers.WithPlugin
import com.tempoplugin.core.workattribute.api.WorkAttributeService
import com.tempoplugin.core.workattribute.api.WorkAttributeValueService

@WithPlugin("is.origo.jira.tempo-plugin")

@PluginModule
WorkAttributeService workAttributeService

@PluginModule
WorkAttributeValueService workAttributeValueService

def worklogManager = ComponentAccessor.worklogManager

def worklogs = worklogManager.getByIssue(issue)

def attribute = workAttributeService.getWorkAttributeByKey("Tempo.WorklogBilledHours").returnedValue

worklogs.sum { Worklog worklog ->
workAttributeValueService.getWorkAttributeValueByWorklogAndWorkAttribute(worklog.id, attribute.id).returnedValue
} as Long
Jens Kisters __SeibertSolutions
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.
September 9, 2020

Hi Alexander.

thanks that looks awesome.

I will try this out.

You should put that in your public docs if it isnt.

Would also make a nice contribution to the adaptavist libary.

Good Luck for your webinar with Andreas today!

kind regards

Jens

Alexander Eck [Tempo]
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.
September 10, 2020

Jens,

will do once you confirmed that it is working (and how). 

Keep us posted!

BR

Jens Kisters __SeibertSolutions
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.
September 10, 2020

Hi Alexander, 
i cant get the last few lines to work,

the return value of 

workAttributeValueService.getWorkAttributeValueByWorklogAndWorkAttribute(worklog.id, attribute.id).returnedValue

 

seems to be a
com.tempoplugin.core.workattribute.api.WorkAttributeValue
and i don't know how to access the number of billed time on that object.

 

Any clues?

kind regards

Jens

Alexander Eck [Tempo]
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.
September 11, 2020

Jens,

a hint would be:

getValue()

BR 

Jens Kisters __SeibertSolutions
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.
September 11, 2020

Alexander,
that hint was helpful. 
I've slighty rewritten the end of the script to fall back to the logged time if the billed time is empty and the working version looks like this:

def attribute = workAttributeService.getWorkAttributeByKey("Tempo.WorklogBilledHours").returnedValue
Long sum = 0L

Iterator wlIterator = worklogs.iterator()
while (wlIterator.hasNext()) {
Worklog worklog = wlIterator.next()
def value = workAttributeValueService.getWorkAttributeValueByWorklogAndWorkAttribute(worklog.id, attribute.id).returnedValue

if (value != null) {
Long longValue = Long.parseLong(value.getValue())
sum += longValue
} else {
log.error worklog.getTimeSpent()
sum += worklog.getTimeSpent()
}
}
0 votes
Answer accepted
Jens Kisters __SeibertSolutions
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.
September 11, 2020

@Alexander Eck [Tempo] , thanks a lot for your helpful input.

You dont happen to have a similar script ready that allows me to extract expenses via the Java API?

Have a nice weekend.

Alexander Eck [Tempo]
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.
September 11, 2020

Hi Jens,

no not really. Maybe you can try:


import com.tempoplugin.core.expense.api.Expense;
import com.tempoplugin.core.expense.api.ExpenseService;

getExpensesByScope(@Nonnull ScopeType scopeType, Long... scope)
getExpensesByScopeAndDate(Pair<LocalDate, LocalDate> duration, Expense.ScopeType scopeType, Long... scope)

with ScopeType = ISSUE.

You might also take a look at the REST API documentation.

Have a good one.

BR

0 votes
Jens Kisters __SeibertSolutions
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.
November 24, 2020

@Alexander Eck [Tempo] thanks for your input again!

We are now looking to do the same for the planned time, do you happen to have a Java code snippet for that as well?

0 votes
Aron Gombas _Midori_
Community Champion
September 9, 2020

Cache the sum (I don't know where to store) and recalculate only if the issue's update date changes?

Jens Kisters __SeibertSolutions
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.
September 9, 2020

Yeah thats one option i was considering, i'd make a static groovy class and use that one as a cache.

Cheers

Jens

Suggest an answer

Log in or Sign up to answer