Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,5 @@ default boolean isTransactional() {
* @param e the exception reason - could also be a {@link FailTaskNoRetryException}
* @see <a href="https://spring-persistent-task.sterl.org/failed-spring-triggers/">Failed trigger</a>
*/
default void afterTriggerFailed(@Nullable T state, Exception e) {
}
default void afterTriggerFailed(@Nullable T state, Exception e) {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
import org.sterl.spring.persistent_tasks.shared.model.TriggerEntity;
import org.sterl.spring.persistent_tasks.trigger.component.StateSerializer;

import lombok.extern.slf4j.Slf4j;

@Slf4j
public enum ToTrigger implements ExtendetConvert<HasTrigger, Trigger> {
INSTANCE;

Expand All @@ -29,8 +32,25 @@ public Trigger convert(@NonNull HasTrigger hasData) {
result.setRunAt(source.getRunAt());
result.setRunningDurationInMs(source.getRunningDurationInMs());
result.setStart(source.getStart());
result.setState(SERIALIZER.deserialize(source.getState()));
try {
result.setState(SERIALIZER.deserialize(source.getState()));
} catch (Exception e) {
var info = """
Failed to deserialize state
This is most likely due to an incompatible code change.
Old states in the DB cannot be read anymore/deserialized and cast to the given class.
""";
result.setState(new FailedToReadStateInfo(e.getMessage(), info));
log.warn("""
Failed to deserialize state of {}.
This is most likely due to an incompatible code change.
Old states in the DB cannot be read anymore/deserialized and cast to the given class.
{}""",
source.getKey(), e.getMessage());
}
result.setStatus(source.getStatus());
return result;
}

record FailedToReadStateInfo(String message, String info) {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -77,9 +77,9 @@ public Page<RunningTriggerEntity> searchTriggers(@Nullable TriggerSearch search,
return result;
} else {
log.debug("Empty search={}, selecting all triggers for page={}", search, page);
return triggerRepository.findAll(page);
var result = triggerRepository.findAll(page);
return result;
}

}

public Page<TriggerGroup> searchGroupedTriggers(@Nullable TriggerSearch search, Pageable page) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInput;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.ObjectStreamClass;
import java.io.Serializable;

import org.sterl.spring.persistent_tasks.exception.SpringPersistentTaskException;
Expand Down Expand Up @@ -50,7 +52,7 @@ public Serializable deserialize(byte[] bytes) {
}

var bis = new ByteArrayInputStream(bytes);
try (ObjectInput in = new ObjectInputStream(bis)) {
try (var in = new ContextClassLoaderObjectInputStream(bis)) {
return (Serializable)in.readObject();
} catch (Exception ex) {
throw new DeSerializationFailedException(bytes, ex);
Expand All @@ -65,4 +67,18 @@ public Serializable deserializeOrNull(byte[] bytes) {
return null;
}
}

// needed for spring boot developer tools
// https://github.com/sterlp/spring-persistent-tasks/issues/19
static class ContextClassLoaderObjectInputStream extends ObjectInputStream {
ContextClassLoaderObjectInputStream(InputStream in) throws IOException {
super(in);
}
@Override
protected Class<?> resolveClass(ObjectStreamClass desc)
throws IOException, ClassNotFoundException {
return Class.forName(desc.getName(), false,
Thread.currentThread().getContextClassLoader());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.github.f4b6a3.uuid.UuidCreator;

class TriggerResourceTest extends AbstractSpringTest {

Expand Down Expand Up @@ -217,6 +218,27 @@ void testGroupSearch() throws JsonMappingException, JsonProcessingException {
assertThat(result.getBody()).contains("\"groupByValue\":\"a1\"");
}

@Test
void testReadIncompatibleTriggerState() {
// GIVEN we have a bad state we cannot read in the DB
var key = UuidCreator.getTimeOrdered().toString();
trx.execute(t -> {
return triggerRepository.save(new RunningTriggerEntity(
new TriggerKey(key, "slowTask")
).withState(new byte[] {12, 54, 33})
);
});

// WHEN
assertThat(triggerRepository.count()).isGreaterThanOrEqualTo(1L);
var response = template.getForEntity(baseUrl, String.class);

// THEN
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
assertThat(response.getBody()).contains(key);
assertThat(response.getBody()).contains("Failed to deserialize state of length");
}

private RunningTriggerEntity createStatus(TriggerKey key, TriggerStatus status) {
final var now = OffsetDateTime.now();
final var isCancel = status == TriggerStatus.CANCELED;
Expand Down
29 changes: 21 additions & 8 deletions example/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
<!--
<spt.version>2.1.2</spt.version>
-->
<spt.version>2.2.3-SNAPSHOT</spt.version>
<spt.version>2.2.4-SNAPSHOT</spt.version>
</properties>

<dependencies>
Expand Down Expand Up @@ -48,12 +48,6 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-envers</artifactId>
</dependency>


<dependency>
<groupId>org.springframework.boot</groupId>
Expand All @@ -69,7 +63,7 @@
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
<version>2.6.0</version>
<version>2.8.13</version>
</dependency>

<dependency>
Expand Down Expand Up @@ -98,5 +92,24 @@
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>