From a1cc61f104673837cee21c89b315013fa3c8d1ac Mon Sep 17 00:00:00 2001 From: "Andrey Rusakov (andrey.rusakov@camptocamp.com)" Date: Thu, 29 Jan 2026 11:24:18 +0100 Subject: [PATCH 1/4] Fix missing HibernateAccounting class --- .../servlet/job/HibernateAccountingEntry.java | 3 +++ .../servlet/job/impl/hibernate/PrintJobDao.java | 16 ++++------------ .../main/resources/mapfish-spring-hibernate.xml | 1 + 3 files changed, 8 insertions(+), 12 deletions(-) diff --git a/core/src/main/java/org/mapfish/print/servlet/job/HibernateAccountingEntry.java b/core/src/main/java/org/mapfish/print/servlet/job/HibernateAccountingEntry.java index fcfee8621c..a2a6f6c31d 100644 --- a/core/src/main/java/org/mapfish/print/servlet/job/HibernateAccountingEntry.java +++ b/core/src/main/java/org/mapfish/print/servlet/job/HibernateAccountingEntry.java @@ -7,6 +7,8 @@ import jakarta.persistence.Id; import jakarta.persistence.Table; import java.util.Date; +import org.hibernate.annotations.JdbcTypeCode; +import org.hibernate.type.SqlTypes; import org.mapfish.print.Constants; import org.mapfish.print.config.Configuration; import org.mapfish.print.processor.ExecutionStats; @@ -56,6 +58,7 @@ public class HibernateAccountingEntry { private Long fileSize = null; @Column(columnDefinition = "jsonb") + @JdbcTypeCode(SqlTypes.JSON) private ObjectNode stats = null; @Column(nullable = false) diff --git a/core/src/main/java/org/mapfish/print/servlet/job/impl/hibernate/PrintJobDao.java b/core/src/main/java/org/mapfish/print/servlet/job/impl/hibernate/PrintJobDao.java index f6ba6e6477..6f1a157fb2 100644 --- a/core/src/main/java/org/mapfish/print/servlet/job/impl/hibernate/PrintJobDao.java +++ b/core/src/main/java/org/mapfish/print/servlet/job/impl/hibernate/PrintJobDao.java @@ -2,7 +2,6 @@ import jakarta.annotation.Nullable; import jakarta.annotation.PostConstruct; -import jakarta.persistence.PessimisticLockException; import jakarta.persistence.criteria.CriteriaBuilder; import jakarta.persistence.criteria.CriteriaDelete; import jakarta.persistence.criteria.CriteriaQuery; @@ -11,7 +10,6 @@ import jakarta.persistence.criteria.Root; import java.net.URI; import java.util.Arrays; -import java.util.Collections; import java.util.List; import org.hibernate.LockMode; import org.hibernate.Session; @@ -223,16 +221,10 @@ public final List poll(final int size) { criteria.orderBy(builder.asc(root.get("entry").get("startTime"))); final Query query = getSession().createQuery(criteria); query.setMaxResults(size); - // LOCK but don't wait for release (since this is run continuously - // anyway, no wait prevents deadlock) - query.setLockMode("pj", LockMode.PESSIMISTIC_WRITE); - query.setHint("jakarta.persistence.lock.timeout", 0); - try { - return query.getResultList(); - } catch (PessimisticLockException ex) { - // Another process was polling at the same time. We can ignore this error - return Collections.emptyList(); - } + // If the row is locked, it means that some other worker is already working on it and + // the current worker doesn't need it anyway. + query.setLockMode("pj", LockMode.UPGRADE_SKIPLOCKED); + return query.getResultList(); } /** diff --git a/core/src/main/resources/mapfish-spring-hibernate.xml b/core/src/main/resources/mapfish-spring-hibernate.xml index e75a99d115..519bbb43e6 100644 --- a/core/src/main/resources/mapfish-spring-hibernate.xml +++ b/core/src/main/resources/mapfish-spring-hibernate.xml @@ -10,6 +10,7 @@ + org.mapfish.print.servlet.job org.mapfish.print.servlet.job.impl org.mapfish.print.servlet.job.impl.hibernate From eb27b1bea8500139a827f93806418d2fd310ed4c Mon Sep 17 00:00:00 2001 From: "Andrey Rusakov (andrey.rusakov@camptocamp.com)" Date: Mon, 2 Feb 2026 17:06:21 +0100 Subject: [PATCH 2/4] More clear code comments. Returned the timeout hint. --- .../print/servlet/job/impl/hibernate/PrintJobDao.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/org/mapfish/print/servlet/job/impl/hibernate/PrintJobDao.java b/core/src/main/java/org/mapfish/print/servlet/job/impl/hibernate/PrintJobDao.java index 6f1a157fb2..6baf3ab576 100644 --- a/core/src/main/java/org/mapfish/print/servlet/job/impl/hibernate/PrintJobDao.java +++ b/core/src/main/java/org/mapfish/print/servlet/job/impl/hibernate/PrintJobDao.java @@ -221,9 +221,10 @@ public final List poll(final int size) { criteria.orderBy(builder.asc(root.get("entry").get("startTime"))); final Query query = getSession().createQuery(criteria); query.setMaxResults(size); - // If the row is locked, it means that some other worker is already working on it and - // the current worker doesn't need it anyway. + // If the row is locked, it means that the row is already taken by some other worker. + // So, this row must not be returned as it's not in a WAITING state. query.setLockMode("pj", LockMode.UPGRADE_SKIPLOCKED); + query.setHint("jakarta.persistence.lock.timeout", 0); return query.getResultList(); } From ef04b27ca2a74892040a2fa0042f55f496a0c456 Mon Sep 17 00:00:00 2001 From: "Andrey Rusakov (andrey.rusakov@camptocamp.com)" Date: Fri, 6 Feb 2026 09:54:55 +0100 Subject: [PATCH 3/4] Explicitly define type for the string fields --- .../servlet/job/HibernateAccountingEntry.java | 11 ++++++----- .../mapfish/print/servlet/job/PrintJobEntry.java | 4 ++-- .../servlet/job/impl/PrintJobResultImpl.java | 15 ++++++++++----- .../servlet/job/impl/PrintJobStatusImpl.java | 6 ++++-- 4 files changed, 22 insertions(+), 14 deletions(-) diff --git a/core/src/main/java/org/mapfish/print/servlet/job/HibernateAccountingEntry.java b/core/src/main/java/org/mapfish/print/servlet/job/HibernateAccountingEntry.java index a2a6f6c31d..d6dea5e4aa 100644 --- a/core/src/main/java/org/mapfish/print/servlet/job/HibernateAccountingEntry.java +++ b/core/src/main/java/org/mapfish/print/servlet/job/HibernateAccountingEntry.java @@ -27,13 +27,14 @@ public class HibernateAccountingEntry { private static final Logger LOGGER = LoggerFactory.getLogger(HibernateAccountingEntry.class); @Id - @Column(name = "reference_id") + @Column(name = "reference_id", columnDefinition = "TEXT") private String referenceId; - @Column(nullable = false, name = "app_id") + @Column(nullable = false, name = "app_id", columnDefinition = "TEXT") private String appId; - @Column private String referrer; + @Column(columnDefinition = "TEXT") + private String referrer; @Column(nullable = false) @Enumerated(EnumType.STRING) @@ -48,10 +49,10 @@ public class HibernateAccountingEntry { @Column(name = "total_time_ms", nullable = false) private long totalTimeMS; - @Column(nullable = false, name = "output_format") + @Column(nullable = false, name = "output_format", columnDefinition = "TEXT") private String outputFormat; - @Column(nullable = false) + @Column(nullable = false, columnDefinition = "TEXT") private String layout; @Column(name = "file_size") diff --git a/core/src/main/java/org/mapfish/print/servlet/job/PrintJobEntry.java b/core/src/main/java/org/mapfish/print/servlet/job/PrintJobEntry.java index e3e68d38ae..1ba8817d88 100644 --- a/core/src/main/java/org/mapfish/print/servlet/job/PrintJobEntry.java +++ b/core/src/main/java/org/mapfish/print/servlet/job/PrintJobEntry.java @@ -19,10 +19,10 @@ @Embeddable public class PrintJobEntry { - @Column(insertable = false, updatable = false) + @Column(insertable = false, updatable = false, columnDefinition = "TEXT") private String referenceId; - @Column() + @Column(columnDefinition = "TEXT") @Type(PJsonObjectUserType.class) private PJsonObject requestData; diff --git a/core/src/main/java/org/mapfish/print/servlet/job/impl/PrintJobResultImpl.java b/core/src/main/java/org/mapfish/print/servlet/job/impl/PrintJobResultImpl.java index d0c1b6d821..3838a6964b 100644 --- a/core/src/main/java/org/mapfish/print/servlet/job/impl/PrintJobResultImpl.java +++ b/core/src/main/java/org/mapfish/print/servlet/job/impl/PrintJobResultImpl.java @@ -20,20 +20,25 @@ @Table(name = "print_job_results") public class PrintJobResultImpl implements PrintJobResult { - @Id private String reportURI; + @Id + @Column(columnDefinition = "TEXT") + private String reportURI; - @Column private String mimeType; + @Column(columnDefinition = "TEXT") + private String mimeType; - @Column private String fileExtension; + @Column(columnDefinition = "TEXT") + private String fileExtension; - @Column private String fileName; + @Column(columnDefinition = "TEXT") + private String fileName; @OneToOne(targetEntity = PrintJobStatusImpl.class, fetch = FetchType.LAZY) @OnDelete(action = OnDeleteAction.CASCADE) @JoinColumn(name = "referenceId", insertable = false, updatable = false) private PrintJobStatus status = null; - @Column(insertable = true, updatable = true) + @Column(insertable = true, updatable = true, columnDefinition = "TEXT") private String referenceId; /** Default Constructor. */ diff --git a/core/src/main/java/org/mapfish/print/servlet/job/impl/PrintJobStatusImpl.java b/core/src/main/java/org/mapfish/print/servlet/job/impl/PrintJobStatusImpl.java index ef832fb123..1b6383dbed 100644 --- a/core/src/main/java/org/mapfish/print/servlet/job/impl/PrintJobStatusImpl.java +++ b/core/src/main/java/org/mapfish/print/servlet/job/impl/PrintJobStatusImpl.java @@ -23,7 +23,9 @@ public class PrintJobStatusImpl implements PrintJobStatus { @Embedded private PrintJobEntry entry; - @Id private String referenceId; + @Id + @Column(columnDefinition = "TEXT") + private String referenceId; @Column @Enumerated(EnumType.STRING) @@ -33,7 +35,7 @@ public class PrintJobStatusImpl implements PrintJobStatus { @Column private long requestCount; - @Column(length = 4096) + @Column(columnDefinition = "TEXT") private String error; @OneToOne(targetEntity = PrintJobResultImpl.class, cascade = CascadeType.ALL, mappedBy = "status") From 81c6c88d6e12b586857e5dde4f9c4acd1a7a4620 Mon Sep 17 00:00:00 2001 From: sebr72 <48369171+sebr72@users.noreply.github.com> Date: Tue, 10 Feb 2026 14:18:53 +0100 Subject: [PATCH 4/4] Update core/src/main/java/org/mapfish/print/servlet/job/impl/hibernate/PrintJobDao.java Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../print/servlet/job/impl/hibernate/PrintJobDao.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/org/mapfish/print/servlet/job/impl/hibernate/PrintJobDao.java b/core/src/main/java/org/mapfish/print/servlet/job/impl/hibernate/PrintJobDao.java index 6baf3ab576..6d0ef1c19c 100644 --- a/core/src/main/java/org/mapfish/print/servlet/job/impl/hibernate/PrintJobDao.java +++ b/core/src/main/java/org/mapfish/print/servlet/job/impl/hibernate/PrintJobDao.java @@ -221,8 +221,9 @@ public final List poll(final int size) { criteria.orderBy(builder.asc(root.get("entry").get("startTime"))); final Query query = getSession().createQuery(criteria); query.setMaxResults(size); - // If the row is locked, it means that the row is already taken by some other worker. - // So, this row must not be returned as it's not in a WAITING state. + // Use SKIP LOCKED so that rows currently locked by other transactions (for example, + // because another worker is in the process of taking them) are simply skipped and + // not returned to this worker, even if their status is still WAITING in the database. query.setLockMode("pj", LockMode.UPGRADE_SKIPLOCKED); query.setHint("jakarta.persistence.lock.timeout", 0); return query.getResultList();