Files
Flash5/pom.xml
T
Zakaria El OrcheandClaude Opus 5 5c163b7f8d feat(ext-scheduler): add interval and cron background jobs
jobs.every(Duration.ofMinutes(5), reports::refresh);
    jobs.cron("0 0 3 * * *", archive::sweep);

One daemon platform thread keeps time; every job body runs on a virtual thread,
so a slow job delays nothing but its own next run and cannot occupy the timer.

Cron expressions compile once into a bitmask per field — a long for seconds and
minutes, an int for the rest — so matching an instant is a shift and a mask
rather than a parse or a set lookup. Next-fire advances by the largest unit
that cannot match instead of ticking second by second, so a yearly expression
resolves in a few dozen iterations rather than thirty million. Five or six
fields, ranges, steps, lists, named months and weekdays, both Sunday encodings,
and the standard union semantics when both day fields are restricted. A
malformed expression throws when the job is registered, not when it would have
fired.

Overlapping runs are skipped, and deliberately not configurable: two copies of
one job at once is a bug in every case anyone has needed, and a flag would only
let it be set wrongly. A skipped run logs how long the previous one has been
going.

A throwing job is logged and keeps its schedule. scheduleAtFixedRate cancels
the task on first exception, silently — a job that dies at 3am and is never
heard from again is the failure this avoids.

Shutdown goes through FlashContext.onClose, so app.stop() drains HTTP first,
then gives running jobs a grace period before forcing them down. Nothing runs
after the app stops. The grace period is the only knob.

Known ceiling, marked in the source: schedules are per-instance, so two
replicas run every job twice. A distributed lock should not exist until there
is a second replica.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-09 12:23:34 +00:00

292 lines
12 KiB
XML

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>dev.relism</groupId>
<artifactId>flash-parent</artifactId>
<version>2.1.0-SNAPSHOT</version>
<packaging>pom</packaging>
<modules>
<module>flash</module>
<module>flash-testing</module>
<module>flash-extensions</module>
</modules>
<distributionManagement>
<repository>
<id>Personal</id>
<url>https://maven.relism.dev/releases</url>
</repository>
<snapshotRepository>
<id>Personal-snapshots</id>
<url>https://maven.relism.dev/snapshots</url>
</snapshotRepository>
</distributionManagement>
<properties>
<maven.compiler.source>21</maven.compiler.source>
<maven.compiler.target>21</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<lombok.version>1.18.44</lombok.version>
<slf4j.version>2.0.16</slf4j.version>
<maven.javadoc.plugin.version>3.11.2</maven.javadoc.plugin.version>
<maven.source.plugin.version>3.3.1</maven.source.plugin.version>
<maven.gpg.plugin.version>3.2.8</maven.gpg.plugin.version>
<maven.versions.plugin.version>2.18.0</maven.versions.plugin.version>
<jmh.version>1.37</jmh.version>
<junit.version>5.11.0</junit.version>
<build.helper.plugin.version>3.6.0</build.helper.plugin.version>
</properties>
<repositories>
<!--
maven.relism.dev went down; fpr-core's source (dev.relism/FastPathRouter) now
publishes to Gitea's own Maven registry instead, via that repo's
.gitea/workflows/publish-maven.yml (same pattern as this project's own). Public repo
owned by a public Gitea user, so this resolves anonymously — no credentials needed.
-->
<repository>
<id>gitea-fastpathrouter</id>
<name>Gitea Maven Registry (Relism/FastPathRouter)</name>
<url>https://git.pixel-services.com/api/packages/Relism/maven</url>
</repository>
</repositories>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>dev.relism</groupId>
<artifactId>flash</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>dev.relism</groupId>
<artifactId>flash-testing</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>dev.relism</groupId>
<artifactId>flash-ext-scheduler</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>dev.relism</groupId>
<artifactId>flash-ext-jackson</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>dev.relism</groupId>
<artifactId>flash-ext-openapi</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>dev.relism</groupId>
<artifactId>flash-ext-oidc</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>dev.relism</groupId>
<artifactId>flash-ext-routeviewer</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>dev.relism</groupId>
<artifactId>flash-ext-view-core</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>dev.relism</groupId>
<artifactId>flash-ext-view-jte</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>dev.relism</groupId>
<artifactId>flash-ext-view-thymeleaf</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>dev.relism</groupId>
<artifactId>flash-ext-limiter</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>dev.relism</groupId>
<artifactId>flash-ext-web-bundler</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>dev.relism</groupId>
<artifactId>flash-ext-mcp</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>dev.relism</groupId>
<artifactId>fpr-core</artifactId>
<!-- Gitea can't republish an existing name+version, so FastPathRouter's CI
stamps a commit-scoped version on every push — see its own
.gitea/workflows/publish-maven.yml. Bump by hand to pick up newer
FastPathRouter changes, same precedent as Pathway's flash.version. -->
<version>1.1.0-36216cd</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>${slf4j.version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>${junit.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.2.5</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<annotationProcessorPaths>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>${maven.source.plugin.version}</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>${maven.javadoc.plugin.version}</version>
<configuration>
<source>${maven.compiler.source}</source>
<encoding>${project.build.sourceEncoding}</encoding>
<doclint>none</doclint>
<failOnError>true</failOnError>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
<version>${maven.gpg.plugin.version}</version>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>versions-maven-plugin</artifactId>
<version>${maven.versions.plugin.version}</version>
<configuration>
<generateBackupPoms>false</generateBackupPoms>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-deploy-plugin</artifactId>
<version>3.1.2</version>
</plugin>
</plugins>
</pluginManagement>
</build>
<profiles>
<profile>
<id>attach-artifacts</id>
<activation>
<file>
<exists>src/main/java</exists>
</file>
</activation>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<executions>
<execution>
<id>attach-sources</id>
<phase>verify</phase>
<goals>
<goal>jar-no-fork</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<executions>
<execution>
<id>attach-javadocs</id>
<phase>verify</phase>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
<profile>
<id>sign-artifacts</id>
<activation>
<property>
<name>performRelease</name>
<value>true</value>
</property>
</activation>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
<executions>
<execution>
<id>sign-artifacts</id>
<phase>verify</phase>
<goals>
<goal>sign</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>