Skip to content

Commit db9b4bd

Browse files
authored
Hindre out of memory ved brevgenerering ved å begrense antallet samtidige håndteringer (flyttet semafor mer sentralt) (#148)
1 parent 4dbc7c9 commit db9b4bd

File tree

3 files changed

+52
-38
lines changed

3 files changed

+52
-38
lines changed

formidling/src/main/java/no/nav/ung/sak/formidling/BrevGenerererTjeneste.java

+11-19
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,7 @@
11
package no.nav.ung.sak.formidling;
22

33

4-
import java.time.Duration;
5-
import java.time.Instant;
6-
import java.util.Objects;
7-
8-
import org.slf4j.Logger;
9-
import org.slf4j.LoggerFactory;
10-
4+
import io.opentelemetry.instrumentation.annotations.WithSpan;
115
import jakarta.enterprise.context.ApplicationScoped;
126
import jakarta.inject.Inject;
137
import no.nav.fpsak.tidsserie.LocalDateTimeline;
@@ -27,6 +21,10 @@
2721
import no.nav.ung.sak.typer.AktørId;
2822
import no.nav.ung.sak.ytelse.DagsatsOgUtbetalingsgrad;
2923
import no.nav.ung.sak.ytelse.beregning.TilkjentYtelseUtleder;
24+
import org.slf4j.Logger;
25+
import org.slf4j.LoggerFactory;
26+
27+
import java.util.Objects;
3028

3129
@ApplicationScoped
3230
public class BrevGenerererTjeneste {
@@ -60,38 +58,32 @@ public BrevGenerererTjeneste(
6058
public BrevGenerererTjeneste() {
6159
}
6260

61+
@WithSpan
6362
public GenerertBrev genererVedtaksbrev(Long behandlingId) {
64-
Instant metodeStart = Instant.now();
63+
return BrevGenereringSemafor.begrensetParallellitet( () -> doGenererVedtaksbrev(behandlingId));
64+
}
6565

66+
@WithSpan //WithSpan her for å kunne skille ventetid på semafor i opentelemetry
67+
private GenerertBrev doGenererVedtaksbrev(Long behandlingId) {
6668
var behandling = behandlingRepository.hentBehandling(behandlingId);
6769
if (!behandling.erAvsluttet()) {
6870
throw new IllegalStateException("Behandling må være avsluttet for å kunne bestille vedtaksbrev");
6971
}
7072

71-
LocalDateTimeline<DagsatsOgUtbetalingsgrad> tilkjentYtelseTidslinje =
72-
tilkjentYtelseUtleder.utledTilkjentYtelseTidslinje(behandlingId);
73+
LocalDateTimeline<DagsatsOgUtbetalingsgrad> tilkjentYtelseTidslinje = tilkjentYtelseUtleder.utledTilkjentYtelseTidslinje(behandlingId);
7374
if (tilkjentYtelseTidslinje.isEmpty()) {
7475
LOG.warn("Behandling har ingen tilkjent ytelse. Støtter ikke vedtaksbrev for avslag foreløpig. BehandlingResultat={}", behandling.getBehandlingResultatType());
7576
return null;
7677
}
77-
7878
var pdlMottaker = hentMottaker(behandling);
79-
80-
var innholdTid = Instant.now();
8179
var resultat = innvilgelseInnholdBygger.bygg(behandling);
82-
LOG.info("Tid bygger: {} ms", Duration.between(innholdTid, Instant.now()).toMillis());
83-
84-
8580
var input = new TemplateInput(resultat.templateType(),
8681
new TemplateDto(
8782
FellesDto.automatisk(new MottakerDto(pdlMottaker.navn(), pdlMottaker.fnr())),
8883
resultat.templateInnholdDto()
8984
)
9085
);
91-
9286
PdfGenDokument dokument = pdfGen.lagDokument(input);
93-
94-
LOG.info("Tid vedtaksbrev: {} ms", Duration.between(metodeStart, Instant.now()).toMillis());
9587
return new GenerertBrev(
9688
dokument,
9789
pdlMottaker,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package no.nav.ung.sak.formidling;
2+
3+
import no.nav.k9.felles.konfigurasjon.env.Environment;
4+
import org.slf4j.Logger;
5+
import org.slf4j.LoggerFactory;
6+
7+
import java.util.concurrent.Semaphore;
8+
import java.util.function.Supplier;
9+
10+
public class BrevGenereringSemafor {
11+
12+
private static final Logger LOG = LoggerFactory.getLogger(BrevGenereringSemafor.class);
13+
14+
private static final Integer MAX_SAMTIDIGE = Environment.current().getProperty("BREVGENERERING_MAX_ANTALL_SAMTIDIGE", Integer.class, 2);
15+
private static final Semaphore SEMAFOR = new Semaphore(MAX_SAMTIDIGE);
16+
17+
private BrevGenereringSemafor() {
18+
}
19+
20+
public static <T> T begrensetParallellitet(Supplier<T> supplier) {
21+
try {
22+
long t0 = System.nanoTime();
23+
SEMAFOR.acquire();
24+
long t1 = System.nanoTime();
25+
long ventetidMillis = (t1 - t0) / 1_000_000;
26+
if (ventetidMillis > 2000) {
27+
LOG.warn("Ventet i {} ms på å få semafor for brevbestilling, skjer dette ofte bør semaforens antall og nodens minne økes for bedre ytelse", ventetidMillis);
28+
}
29+
} catch (InterruptedException e) {
30+
throw new RuntimeException(e);
31+
}
32+
try {
33+
return supplier.get();
34+
} finally {
35+
SEMAFOR.release();
36+
}
37+
38+
}
39+
40+
}

web/src/main/java/no/nav/ung/sak/web/app/tjenester/formidling/FormidlingRestTjeneste.java

+1-19
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,7 @@
44
import static no.nav.ung.abac.BeskyttetRessursKoder.FAGSAK;
55

66
import java.util.Objects;
7-
import java.util.concurrent.Semaphore;
87

9-
import io.opentelemetry.instrumentation.annotations.WithSpan;
108
import org.slf4j.Logger;
119
import org.slf4j.LoggerFactory;
1210

@@ -56,9 +54,6 @@ public class FormidlingRestTjeneste {
5654
private static final String PDF_MEDIA_STRING = "application/pdf";
5755
private static final MediaType PDF_MEDIA_TYPE = MediaType.valueOf(PDF_MEDIA_STRING);
5856

59-
private static final int MAX_ANTALL_SAMTIDIGE_FORHÅNDSVISNINGER = 2; //kan justeres sammen med minne for applikasjonen
60-
private static final Semaphore SEMAFOR_SAMTIDIGE_FORHÅNDSVISNINGER = new Semaphore(MAX_ANTALL_SAMTIDIGE_FORHÅNDSVISNINGER);
61-
6257
@Inject
6358
public FormidlingRestTjeneste(
6459
BrevGenerererTjeneste brevGenerererTjeneste,
@@ -114,20 +109,8 @@ public VedtaksbrevOperasjonerDto tilgjengeligeVedtaksbrev(
114109
public Response forhåndsvisVedtaksbrev(
115110
@NotNull @Parameter(description = "") @Valid @TilpassetAbacAttributt(supplierClass = AbacAttributtSupplier.class) VedtaksbrevForhåndsvisDto dto,
116111
@Context HttpServletRequest request
117-
) throws InterruptedException {
118-
// Semafor her for å begrense hvor mange samtidige forhåndsvisninger som kjøres for å unngå OutOfMemoryError.
119-
// Operasjonen både bruker noe tid, og mye minne, så uten begrensning er det er fullt mulig å knele applikasjonen
120-
// ved å forhåndsvise flere ganger på kort tid.
121-
SEMAFOR_SAMTIDIGE_FORHÅNDSVISNINGER.acquire();
122-
try {
123-
return doForhåndsvisVedtaksbrev(dto, request);
124-
} finally {
125-
SEMAFOR_SAMTIDIGE_FORHÅNDSVISNINGER.release();
126-
}
127-
}
112+
) {
128113

129-
@WithSpan //span her for å kunne skille venting på semafor fra resten
130-
private Response doForhåndsvisVedtaksbrev(VedtaksbrevForhåndsvisDto dto, HttpServletRequest request) {
131114
GenerertBrev generertBrev = brevGenerererTjeneste.genererVedtaksbrev(dto.behandlingId());
132115

133116
var mediaTypeReq = Objects.requireNonNullElse(request.getHeader(HttpHeaders.ACCEPT), MediaType.APPLICATION_OCTET_STREAM);
@@ -142,6 +125,5 @@ public VedtaksbrevOperasjonerDto tilgjengeligeVedtaksbrev(
142125
};
143126
}
144127

145-
146128
}
147129

0 commit comments

Comments
 (0)