Skip to content
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

Lagt til støtte for å kunne kjøre tasks direkte etter lagring #478

Open
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

blommish
Copy link
Collaborator

Det har tidligere vært nevnt behov for dette og føler at det hadde vært fint.

Legger til en metode som lagrer og kaller på pollAndExecute etter transaction.
Hvis man kaller på saveAndRun 2 ganger i en transaction, så blir pollAndExecute kjørt 1 gang, og ikke 1 gang per tilfelle man kaller på pollAndExecute

Pga circular dependency så ble TaskTransactionSynchronization lazy.

@Lazy
private val taskTransactionSynchronization: TaskTransactionSynchronization

For å ikke gå i beina på @Scheduled så la jeg inn en AtomicBoolean.
Planlagt jobb kjører hvert X sekund fra siste planlagte jobb, men den har ikke noe forhold til hvis denne blir kjørt manuellt i mellomtiden.

Den eneste måten som er mulig å trigge selve jobbet manuellt som jeg funnet er noe i stil med

val scheduledTask: ScheduledTask = prosessor.scheduledTasks.single {
        (it.task.runnable as ScheduledMethodRunnable).method.name == "pollAndExecute"
    }
    val declaredField = ScheduledTask::class.java.getDeclaredField("future")
    declaredField.isAccessible = true
    val message = declaredField.get(scheduledTask) as RunnableScheduledFuture<*>
    message.run()

Mulig det finnes andre måter, men denne valgte jeg å ikke gå for.

*/
@Transactional
fun saveAndRun(task: Task): Task {
TransactionSynchronizationManager.registerSynchronization(taskTransactionSynchronization)
Copy link
Contributor

Choose a reason for hiding this comment

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

Hva gjør dette?

Copy link
Contributor

Choose a reason for hiding this comment

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

Stemmer det at dette overstyrer task synkronisteringen slik at vi overstyrer afterCommit?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Overstyrer ikke, vi legger til en hendelse i afterCommit

Copy link
Contributor

@hensol hensol left a comment

Choose a reason for hiding this comment

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

Har lagt inn noen kommentarer.

Men lurer egentlig på er det task rammeverket vi skal bruke når vi ønsker at noe skal kjøre med en gang?

Tar gjerne imot inspill fra andre også på om dette er riktig retning å gå.

Den opprinnelige tanken med task-rammeverket var at det skulle være enkelt, og at det skulle håndtere oppgaver som skulle kjøres asynkront og som det ikke var så viktig at ble utført med en gang.

log.info("Shutting down, does not start new pollAndExecuteTasks")
return
}
if (!pollAndExecuteTasks()) return
Copy link
Contributor

Choose a reason for hiding this comment

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

hvorfor trekkes denne inn i while(true)?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Den fantes der fra før, det har bare blitt noen flere spaces pga wrap med try catch :)
Den er der fra før for å kunne håndtere at man skal prosessere forløpende (continuousRunning)

@ma10s
Copy link

ma10s commented Oct 26, 2023

Det har tidligere vært nevnt behov for dette og føler at det hadde vært fint.

Legger til en metode som lagrer og kaller på pollAndExecute etter transaction. Hvis man kaller på saveAndRun 2 ganger i en transaction, så blir pollAndExecute kjørt 1 gang, og ikke 1 gang per tilfelle man kaller på pollAndExecute

Pga circular dependency så ble TaskTransactionSynchronization lazy.

@Lazy
private val taskTransactionSynchronization: TaskTransactionSynchronization

For å ikke gå i beina på @Scheduled så la jeg inn en AtomicBoolean. Planlagt jobb kjører hvert X sekund fra siste planlagte jobb, men den har ikke noe forhold til hvis denne blir kjørt manuellt i mellomtiden.

Den eneste måten som er mulig å trigge selve jobbet manuellt som jeg funnet er noe i stil med

val scheduledTask: ScheduledTask = prosessor.scheduledTasks.single {
        (it.task.runnable as ScheduledMethodRunnable).method.name == "pollAndExecute"
    }
    val declaredField = ScheduledTask::class.java.getDeclaredField("future")
    declaredField.isAccessible = true
    val message = declaredField.get(scheduledTask) as RunnableScheduledFuture<*>
    message.run()

Mulig det finnes andre måter, men denne valgte jeg å ikke gå for.

Hva er egentlig behovet her - er det å snike i kø, eller er det å "nesten" kjøre synkront, men med mulighet for rekjøring manuelt?

@blommish
Copy link
Collaborator Author

blommish commented Oct 27, 2023

Har lagt inn noen kommentarer.

Men lurer egentlig på er det task rammeverket vi skal bruke når vi ønsker at noe skal kjøre med en gang?

Tar gjerne imot inspill fra andre også på om dette er riktig retning å gå.

Den opprinnelige tanken med task-rammeverket var at det skulle være enkelt, og at det skulle håndtere oppgaver som skulle kjøres asynkront og som det ikke var så viktig at ble utført med en gang.

@ma10s @hensol

Bakgrunnen er å kunne kjøre en task direkte, uten å vente på at det skal gå X sekunder. Men at det skjer i form av en task, uavhengig den tråd som oppretter tasken.
Det er generellt unødvendig å polle databasen allt for ofte, eks 1 gang i sekunder over alle dygnets timer.

Eks når man oppretter en oppgave, eller noe annet, så ønsker vi at det skjer i en egen task (og i egen transaction med egen feilhåndtering), men at det skjer direkte. Behovet har vært diskutert både i EF og BA tidligere. Et tidligere forsøk på det ble gjort i #164 av @hensol

Copy link
Contributor

@hensol hensol left a comment

Choose a reason for hiding this comment

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

Gode argumenter i fht. oppdatering av oppgaver, så jeg har blitt overbevist nå :)
ref. slack tråd https://nav-it.slack.com/archives/CJN0STWB0/p1698241045668649

private val logger = LoggerFactory.getLogger(javaClass)
override fun afterCommit() {
logger.debug("Kaller på pollAndExecute")
taskStepExecutorService.pollAndExecute()
Copy link
Contributor

Choose a reason for hiding this comment

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

Denne kaller ikke nødvendigvis på tasken du akkurat har lagret ned, men tar "neste på lista". Det er jo greit nok for de aller fleste tilfellene, men kan være litt misvisende at det heter saveAndRun - ettersom det egentlig er saveAndPoll.

Eks:

  1. EF kjører g-omregning med X tusen tasker
  2. En saveAndRun på oppdaterOppgave blir opprettet
  3. Da kommer trolig ikke oppdaterOppgaveTasken til å bli kjørt "med en gang"

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Det er sant, har fikset i 1a2837f

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants