Compare commits

..

43 Commits

Author SHA1 Message Date
Loïc Mathieu
b3bbedaeff chore(system): replace DSL.trueCondition by DSL.noCondition
jOOQ will then generates a query with no WHERE clause or no AND clause instead of WHERE true or WHERE 1=1
2025-11-19 13:35:31 +01:00
Piyush Bhaskar
312ec2c36b chore(core): remove import warning (#13071) 2025-11-19 17:27:00 +05:30
Piyush Bhaskar
d57150e69c chore(test): fix frontend failing test (#13070) 2025-11-19 17:23:16 +05:30
Miloš Paunović
4b25232d4e build(core): remove unused dependency (#13064) 2025-11-19 12:33:19 +01:00
Loïc Mathieu
1d1a065833 fix(tests): lower termination grace period
If a test mis-behave, for ex starting an execution but not terminating it, as the default termination grace period is 5mn it can take very long time to wait for post-test terminaison.
Switching to a termination grace period of 5s may help.

I also detect that the ExecutionControllerRunner test when launching the test suite, would not properly kill the `sleep-long` flow so waiting for it to complete, or the termination grace period. When a test that use this flow is launched separatly it works properly. As a safety net I reduce the sleep from 5mn to 30s.
2025-11-19 11:58:06 +01:00
dependabot[bot]
d6ecbadee1 build(deps): bump kafkaVersion from 4.1.0 to 4.1.1
Bumps `kafkaVersion` from 4.1.0 to 4.1.1.

Updates `org.apache.kafka:kafka-clients` from 4.1.0 to 4.1.1

Updates `org.apache.kafka:kafka-streams` from 4.1.0 to 4.1.1

Updates `org.apache.kafka:kafka-streams-test-utils` from 4.1.0 to 4.1.1

---
updated-dependencies:
- dependency-name: org.apache.kafka:kafka-clients
  dependency-version: 4.1.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
- dependency-name: org.apache.kafka:kafka-streams
  dependency-version: 4.1.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
- dependency-name: org.apache.kafka:kafka-streams-test-utils
  dependency-version: 4.1.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-11-19 11:51:01 +01:00
dependabot[bot]
205605060d build(deps): bump com.google.cloud:libraries-bom from 26.71.0 to 26.72.0
Bumps [com.google.cloud:libraries-bom](https://github.com/googleapis/java-cloud-bom) from 26.71.0 to 26.72.0.
- [Release notes](https://github.com/googleapis/java-cloud-bom/releases)
- [Changelog](https://github.com/googleapis/java-cloud-bom/blob/main/release-please-config.json)
- [Commits](https://github.com/googleapis/java-cloud-bom/compare/v26.71.0...v26.72.0)

---
updated-dependencies:
- dependency-name: com.google.cloud:libraries-bom
  dependency-version: 26.72.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-11-19 11:50:38 +01:00
dependabot[bot]
6ef3a00e16 build(deps): bump peter-evans/repository-dispatch from 4.0.0 to 4.0.1
Bumps [peter-evans/repository-dispatch](https://github.com/peter-evans/repository-dispatch) from 4.0.0 to 4.0.1.
- [Release notes](https://github.com/peter-evans/repository-dispatch/releases)
- [Commits](5fc4efd1a4...28959ce8df)

---
updated-dependencies:
- dependency-name: peter-evans/repository-dispatch
  dependency-version: 4.0.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-11-19 11:48:57 +01:00
dependabot[bot]
f70d612878 build(deps): bump actions/github-script from 7 to 8
Bumps [actions/github-script](https://github.com/actions/github-script) from 7 to 8.
- [Release notes](https://github.com/actions/github-script/releases)
- [Commits](https://github.com/actions/github-script/compare/v7...v8)

---
updated-dependencies:
- dependency-name: actions/github-script
  dependency-version: '8'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-11-19 11:48:35 +01:00
dependabot[bot]
0b345c03d1 build(deps): bump net.e175.klaus:zip-prefixer from 0.3.1 to 0.4.0
Bumps [net.e175.klaus:zip-prefixer](https://github.com/klausbrunner/zip-prefixer) from 0.3.1 to 0.4.0.
- [Commits](https://github.com/klausbrunner/zip-prefixer/commits)

---
updated-dependencies:
- dependency-name: net.e175.klaus:zip-prefixer
  dependency-version: 0.4.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-11-19 11:48:03 +01:00
dependabot[bot]
ecb508f797 build(deps): bump io.qameta.allure:allure-bom from 2.30.0 to 2.31.0
Bumps [io.qameta.allure:allure-bom](https://github.com/allure-framework/allure-java) from 2.30.0 to 2.31.0.
- [Release notes](https://github.com/allure-framework/allure-java/releases)
- [Commits](https://github.com/allure-framework/allure-java/compare/2.30.0...2.31.0)

---
updated-dependencies:
- dependency-name: io.qameta.allure:allure-bom
  dependency-version: 2.31.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-11-19 11:47:43 +01:00
dependabot[bot]
38caea2568 build(deps): bump flyingSaucerVersion from 10.0.3 to 10.0.4
Bumps `flyingSaucerVersion` from 10.0.3 to 10.0.4.

Updates `org.xhtmlrenderer:flying-saucer-core` from 10.0.3 to 10.0.4
- [Release notes](https://github.com/flyingsaucerproject/flyingsaucer/releases)
- [Changelog](https://github.com/flyingsaucerproject/flyingsaucer/blob/main/CHANGELOG.md)
- [Commits](https://github.com/flyingsaucerproject/flyingsaucer/compare/v10.0.3...v10.0.4)

Updates `org.xhtmlrenderer:flying-saucer-pdf` from 10.0.3 to 10.0.4
- [Release notes](https://github.com/flyingsaucerproject/flyingsaucer/releases)
- [Changelog](https://github.com/flyingsaucerproject/flyingsaucer/blob/main/CHANGELOG.md)
- [Commits](https://github.com/flyingsaucerproject/flyingsaucer/compare/v10.0.3...v10.0.4)

---
updated-dependencies:
- dependency-name: org.xhtmlrenderer:flying-saucer-core
  dependency-version: 10.0.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
- dependency-name: org.xhtmlrenderer:flying-saucer-pdf
  dependency-version: 10.0.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-11-19 11:47:22 +01:00
dependabot[bot]
cdad732576 build(deps): bump org.wiremock:wiremock-jetty12 from 3.13.1 to 3.13.2
Bumps [org.wiremock:wiremock-jetty12](https://github.com/wiremock/wiremock) from 3.13.1 to 3.13.2.
- [Release notes](https://github.com/wiremock/wiremock/releases)
- [Commits](https://github.com/wiremock/wiremock/compare/3.13.1...3.13.2)

---
updated-dependencies:
- dependency-name: org.wiremock:wiremock-jetty12
  dependency-version: 3.13.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-11-19 11:46:15 +01:00
dependabot[bot]
0dd4cb963f build(deps): bump org.apache.commons:commons-lang3 from 3.19.0 to 3.20.0
Bumps org.apache.commons:commons-lang3 from 3.19.0 to 3.20.0.

---
updated-dependencies:
- dependency-name: org.apache.commons:commons-lang3
  dependency-version: 3.20.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-11-19 11:45:46 +01:00
dependabot[bot]
c35ca82356 build(deps): bump software.amazon.awssdk:bom from 2.38.4 to 2.38.9
Bumps software.amazon.awssdk:bom from 2.38.4 to 2.38.9.

---
updated-dependencies:
- dependency-name: software.amazon.awssdk:bom
  dependency-version: 2.38.9
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-11-19 11:45:21 +01:00
Miloš Paunović
db6cb93df4 chore(deps): regular dependency update (#13065)
Performing a weekly round of dependency updates in the NPM ecosystem to keep everything up to date.
2025-11-19 09:45:28 +01:00
YannC
1f8d2ea918 fix: use pull request head sha instead of commit.sha (#13063) 2025-11-19 09:34:34 +01:00
dependabot[bot]
3c09a38eed build(deps): bump the patch group in /ui with 6 updates (#13057)
Bumps the patch group in /ui with 6 updates:

| Package | From | To |
| --- | --- | --- |
| [el-table-infinite-scroll](https://github.com/yujinpan/el-table-infinite-scroll) | `3.0.7` | `3.0.8` |
| [element-plus](https://github.com/element-plus/element-plus) | `2.11.7` | `2.11.8` |
| [@vitejs/plugin-vue](https://github.com/vitejs/vite-plugin-vue/tree/HEAD/packages/plugin-vue) | `6.0.1` | `6.0.2` |
| [@vitejs/plugin-vue-jsx](https://github.com/vitejs/vite-plugin-vue/tree/HEAD/packages/plugin-vue-jsx) | `5.1.1` | `5.1.2` |
| [rolldown-vite](https://github.com/vitejs/rolldown-vite/tree/HEAD/packages/vite) | `7.2.5` | `7.2.6` |
| [vue-tsc](https://github.com/vuejs/language-tools/tree/HEAD/packages/tsc) | `3.1.3` | `3.1.4` |


Updates `el-table-infinite-scroll` from 3.0.7 to 3.0.8
- [Changelog](https://github.com/yujinpan/el-table-infinite-scroll/blob/v3/CHANGELOG.md)
- [Commits](https://github.com/yujinpan/el-table-infinite-scroll/compare/v3.0.7...v3.0.8)

Updates `element-plus` from 2.11.7 to 2.11.8
- [Release notes](https://github.com/element-plus/element-plus/releases)
- [Changelog](https://github.com/element-plus/element-plus/blob/dev/CHANGELOG.en-US.md)
- [Commits](https://github.com/element-plus/element-plus/compare/2.11.7...2.11.8)

Updates `@vitejs/plugin-vue` from 6.0.1 to 6.0.2
- [Release notes](https://github.com/vitejs/vite-plugin-vue/releases)
- [Changelog](https://github.com/vitejs/vite-plugin-vue/blob/main/packages/plugin-vue/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite-plugin-vue/commits/plugin-vue@6.0.2/packages/plugin-vue)

Updates `@vitejs/plugin-vue-jsx` from 5.1.1 to 5.1.2
- [Release notes](https://github.com/vitejs/vite-plugin-vue/releases)
- [Changelog](https://github.com/vitejs/vite-plugin-vue/blob/main/packages/plugin-vue-jsx/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite-plugin-vue/commits/plugin-vue@5.1.2/packages/plugin-vue-jsx)

Updates `rolldown-vite` from 7.2.5 to 7.2.6
- [Release notes](https://github.com/vitejs/rolldown-vite/releases)
- [Changelog](https://github.com/vitejs/rolldown-vite/blob/rolldown-vite/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/rolldown-vite/commits/v7.2.6/packages/vite)

Updates `vue-tsc` from 3.1.3 to 3.1.4
- [Release notes](https://github.com/vuejs/language-tools/releases)
- [Changelog](https://github.com/vuejs/language-tools/blob/master/CHANGELOG.md)
- [Commits](https://github.com/vuejs/language-tools/commits/v3.1.4/packages/tsc)

---
updated-dependencies:
- dependency-name: el-table-infinite-scroll
  dependency-version: 3.0.8
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: patch
- dependency-name: element-plus
  dependency-version: 2.11.8
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: patch
- dependency-name: "@vitejs/plugin-vue"
  dependency-version: 6.0.2
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: patch
- dependency-name: "@vitejs/plugin-vue-jsx"
  dependency-version: 5.1.2
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: patch
- dependency-name: rolldown-vite
  dependency-version: 7.2.6
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: patch
- dependency-name: vue-tsc
  dependency-version: 3.1.4
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-19 08:54:11 +01:00
dependabot[bot]
0525e3ece6 build(deps): bump the build group in /ui with 6 updates (#13044)
Bumps the build group in /ui with 6 updates:

| Package | From | To |
| --- | --- | --- |
| [@rollup/rollup-darwin-arm64](https://github.com/rollup/rollup) | `4.53.2` | `4.53.3` |
| [@rollup/rollup-darwin-x64](https://github.com/rollup/rollup) | `4.53.2` | `4.53.3` |
| [@rollup/rollup-linux-x64-gnu](https://github.com/rollup/rollup) | `4.53.2` | `4.53.3` |
| [@swc/core-darwin-arm64](https://github.com/swc-project/swc) | `1.15.1` | `1.15.2` |
| [@swc/core-darwin-x64](https://github.com/swc-project/swc) | `1.15.1` | `1.15.2` |
| [@swc/core-linux-x64-gnu](https://github.com/swc-project/swc) | `1.15.1` | `1.15.2` |


Updates `@rollup/rollup-darwin-arm64` from 4.53.2 to 4.53.3
- [Release notes](https://github.com/rollup/rollup/releases)
- [Changelog](https://github.com/rollup/rollup/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rollup/rollup/compare/v4.53.2...v4.53.3)

Updates `@rollup/rollup-darwin-x64` from 4.53.2 to 4.53.3
- [Release notes](https://github.com/rollup/rollup/releases)
- [Changelog](https://github.com/rollup/rollup/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rollup/rollup/compare/v4.53.2...v4.53.3)

Updates `@rollup/rollup-linux-x64-gnu` from 4.53.2 to 4.53.3
- [Release notes](https://github.com/rollup/rollup/releases)
- [Changelog](https://github.com/rollup/rollup/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rollup/rollup/compare/v4.53.2...v4.53.3)

Updates `@swc/core-darwin-arm64` from 1.15.1 to 1.15.2
- [Release notes](https://github.com/swc-project/swc/releases)
- [Changelog](https://github.com/swc-project/swc/blob/main/CHANGELOG.md)
- [Commits](https://github.com/swc-project/swc/compare/v1.15.1...v1.15.2)

Updates `@swc/core-darwin-x64` from 1.15.1 to 1.15.2
- [Release notes](https://github.com/swc-project/swc/releases)
- [Changelog](https://github.com/swc-project/swc/blob/main/CHANGELOG.md)
- [Commits](https://github.com/swc-project/swc/compare/v1.15.1...v1.15.2)

Updates `@swc/core-linux-x64-gnu` from 1.15.1 to 1.15.2
- [Release notes](https://github.com/swc-project/swc/releases)
- [Changelog](https://github.com/swc-project/swc/blob/main/CHANGELOG.md)
- [Commits](https://github.com/swc-project/swc/compare/v1.15.1...v1.15.2)

---
updated-dependencies:
- dependency-name: "@rollup/rollup-darwin-arm64"
  dependency-version: 4.53.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: build
- dependency-name: "@rollup/rollup-darwin-x64"
  dependency-version: 4.53.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: build
- dependency-name: "@rollup/rollup-linux-x64-gnu"
  dependency-version: 4.53.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: build
- dependency-name: "@swc/core-darwin-arm64"
  dependency-version: 1.15.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: build
- dependency-name: "@swc/core-darwin-x64"
  dependency-version: 1.15.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: build
- dependency-name: "@swc/core-linux-x64-gnu"
  dependency-version: 1.15.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: build
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-19 08:31:51 +01:00
MSHIVVANI
4382aabe39 fix(ui): Wrap header actions on Flows page for mobile view (#12976)
Co-authored-by: Miloš Paunović <paun992@hotmail.com>
2025-11-18 18:48:52 +05:30
Mahadeva Peruka
5e0fddadc4 fix(core): Fixed padding for Flow Home page (#12831) 2025-11-18 18:45:35 +05:30
Karthik D
4297459a6a refactor(ui): Convert LogChart.vue component to TS (#12987)
Co-authored-by: Miloš Paunović <paun992@hotmail.com>
2025-11-18 18:34:24 +05:30
Miloš Paunović
31e5f6bdef chore(core): improve handling of local and cdn-loaded fonts (#13020)
Related to https://github.com/kestra-io/kestra/pull/11448#issuecomment-3510236629.

Closes https://github.com/kestra-io/kestra/issues/13019.
2025-11-18 13:25:58 +01:00
github-actions[bot]
dc7cea0396 chore(core): localize to languages other than english (#13021)
Extended localization support by adding translations for multiple languages using English as the base. This enhances accessibility and usability for non-English-speaking users while keeping English as the source reference.

Co-authored-by: GitHub Action <actions@github.com>
2025-11-18 13:25:38 +01:00
Piyush Bhaskar
e818614f4a feat(core): add a empty page for namespace overview (#13017)
Co-authored-by: GitHub Action <actions@github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-11-18 17:39:47 +05:30
dependabot[bot]
a5ccfbb0ac build(deps): bump com.github.ben-manes.caffeine:caffeine
Bumps [com.github.ben-manes.caffeine:caffeine](https://github.com/ben-manes/caffeine) from 3.2.2 to 3.2.3.
- [Release notes](https://github.com/ben-manes/caffeine/releases)
- [Commits](https://github.com/ben-manes/caffeine/compare/v3.2.2...v3.2.3)

---
updated-dependencies:
- dependency-name: com.github.ben-manes.caffeine:caffeine
  dependency-version: 3.2.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-11-18 11:51:51 +01:00
Piyush Bhaskar
e5fece8d4d fix(core): clear the selection properly and refactor (#13012) 2025-11-18 16:07:29 +05:30
brian-mulier-p
816a1bb543 fix(cli): no-args will properly return help (#12980)
closes https://github.com/kestra-io/kestra-ee/issues/5842
2025-11-18 11:23:30 +01:00
Loïc Mathieu
735697ac71 chore(system): share JDBC repository code in an abstract CRUD repository 2025-11-18 11:13:16 +01:00
Ridham Anand
4fc6948037 feat(ui): replace native alert with ElDialog for unsaved changes warning (#12373) (#12475)
Co-authored-by: Miloš Paunović <paun992@hotmail.com>
Co-authored-by: Bart Ledoux <bledoux@kestra.io>
2025-11-18 10:56:22 +01:00
tharani-2006
e56e35e770 Fix: follow timezone from settings when displaying DATETIME KV (#9428) (#12363)
Co-authored-by: Miloš Paunović <paun992@hotmail.com>
2025-11-18 10:24:27 +01:00
Loïc Mathieu
a4ca3498f3 fix(execution): use jdbcRepository.findOne to be tolerant of multiple results
It uses findAny() under the cover which does not throw if more than one result is returned.

Fixes #12943
2025-11-18 10:21:51 +01:00
Barthélémy Ledoux
d7e17f157a fix(flows): synchronize unsaved popup with flow store (#13004)
Co-authored-by: Miloš Paunović <paun992@hotmail.com>
2025-11-18 10:12:26 +01:00
Loïc Mathieu
41f83949f0 chore(system): replace Flow by FlowInterface where possible
Part-of: https://github.com/kestra-io/kestra/issues/8274
2025-11-18 09:50:49 +01:00
Miloš Paunović
0db2d8759a refactor(core): clean up usage of constants throughout the repositories (#13011)
Closes https://github.com/kestra-io/kestra/issues/7905.
2025-11-18 09:50:33 +01:00
YannC
6e0197b542 feat: allows importFlows endpoint to be able to throw when having an invalid flow (#12995) 2025-11-18 09:33:32 +01:00
YannC
6918d5d512 feat: add annotation for multipart body on resumeExecution to have it inside SDK (#13003) 2025-11-18 09:33:21 +01:00
Pradumna Saraf
a3fc9b1532 chore: update the postgresql volume path in compose file (#12946) 2025-11-18 13:43:55 +05:30
Florian Hussonnois
0f340a9a29 fix(scheduler): mysql convert 'now' to UTC to avoid any offset error on next_execution_date
Fixed a previous commit to only apply the change for MySQL

Related-to: kestra-io/kestra-ee#5611
2025-11-17 21:52:58 +01:00
Barthélémy Ledoux
8a8911a25d test(e2e): make e2e tests pass again with restoreUrl (#12887) 2025-11-17 17:51:09 +01:00
Florian Hussonnois
ae204a03b0 fix(scheduler): convert 'now' to UTC to avoid any offset error on next_execution_date
Related-to: kestra-io/kestra-ee#5611
2025-11-17 13:12:31 +01:00
Aleksa Radosavljević
4dc7924184 refactor(core): remove usage of unnecessary i18n composable (#12996)
Closes https://github.com/kestra-io/kestra/issues/12962.

Co-authored-by: Miloš Paunović <paun992@hotmail.com>
2025-11-17 12:46:11 +01:00
Barthélémy Ledoux
748d055183 fix: make custom dashboard fully responsive (#12992) 2025-11-17 12:24:12 +01:00
176 changed files with 3735 additions and 4535 deletions

View File

@@ -28,7 +28,7 @@ jobs:
steps:
# Targeting develop branch from develop
- name: Trigger EE Workflow (develop push, no payload)
uses: peter-evans/repository-dispatch@5fc4efd1a4797ddb68ffd0714a238564e4cc0e6f
uses: peter-evans/repository-dispatch@28959ce8df70de7be546dd1250a005dd32156697
if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/develop' }}
with:
token: ${{ secrets.GH_PERSONAL_TOKEN }}

View File

@@ -16,7 +16,7 @@ jobs:
- name: Check EE repo for branch with same name
if: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.repo.fork == false }}
id: check-ee-branch
uses: actions/github-script@v7
uses: actions/github-script@v8
with:
github-token: ${{ secrets.GH_PERSONAL_TOKEN }}
script: |
@@ -40,7 +40,7 @@ jobs:
# Targeting pull request (only if not from a fork and EE has no branch with same name)
- name: Trigger EE Workflow (pull request, with payload)
uses: peter-evans/repository-dispatch@5fc4efd1a4797ddb68ffd0714a238564e4cc0e6f
uses: peter-evans/repository-dispatch@28959ce8df70de7be546dd1250a005dd32156697
if: ${{ github.event_name == 'pull_request'
&& github.event.pull_request.number != ''
&& github.event.pull_request.head.repo.fork == false
@@ -50,7 +50,7 @@ jobs:
repository: kestra-io/kestra-ee
event-type: "oss-updated"
client-payload: >-
{"commit_sha":"${{ github.sha }}","pr_repo":"${{ github.repository }}"}
{"commit_sha":"${{ github.event.pull_request.head.sha }}","pr_repo":"${{ github.repository }}"}
file-changes:
if: ${{ github.event.pull_request.draft == false }}

View File

@@ -7,7 +7,7 @@ buildscript {
}
dependencies {
classpath "net.e175.klaus:zip-prefixer:0.3.1"
classpath "net.e175.klaus:zip-prefixer:0.4.0"
}
}

View File

@@ -8,11 +8,10 @@ import io.kestra.cli.commands.plugins.PluginCommand;
import io.kestra.cli.commands.servers.ServerCommand;
import io.kestra.cli.commands.sys.SysCommand;
import io.kestra.cli.commands.templates.TemplateCommand;
import io.kestra.cli.services.EnvironmentProvider;
import io.micronaut.configuration.picocli.MicronautFactory;
import io.micronaut.configuration.picocli.PicocliRunner;
import io.micronaut.context.ApplicationContext;
import io.micronaut.context.ApplicationContextBuilder;
import io.micronaut.context.env.Environment;
import io.micronaut.core.annotation.Introspected;
import org.slf4j.bridge.SLF4JBridgeHandler;
import picocli.CommandLine;
@@ -20,11 +19,9 @@ import picocli.CommandLine;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.*;
import java.util.concurrent.Callable;
import java.util.stream.Stream;
@CommandLine.Command(
name = "kestra",
@@ -49,24 +46,50 @@ import java.util.concurrent.Callable;
@Introspected
public class App implements Callable<Integer> {
public static void main(String[] args) {
execute(App.class, new String [] { Environment.CLI }, args);
System.exit(runCli(args));
}
public static int runCli(String[] args, String... extraEnvironments) {
return runCli(App.class, args, extraEnvironments);
}
public static int runCli(Class<?> cls, String[] args, String... extraEnvironments) {
ServiceLoader<EnvironmentProvider> environmentProviders = ServiceLoader.load(EnvironmentProvider.class);
String[] baseEnvironments = environmentProviders.findFirst().map(EnvironmentProvider::getCliEnvironments).orElseGet(() -> new String[0]);
return execute(
cls,
Stream.concat(
Arrays.stream(baseEnvironments),
Arrays.stream(extraEnvironments)
).toArray(String[]::new),
args
);
}
@Override
public Integer call() throws Exception {
return PicocliRunner.call(App.class, "--help");
return runCli(new String[0]);
}
protected static void execute(Class<?> cls, String[] environments, String... args) {
protected static int execute(Class<?> cls, String[] environments, String... args) {
// Log Bridge
SLF4JBridgeHandler.removeHandlersForRootLogger();
SLF4JBridgeHandler.install();
// Init ApplicationContext
ApplicationContext applicationContext = App.applicationContext(cls, environments, args);
CommandLine commandLine = getCommandLine(cls, args);
ApplicationContext applicationContext = App.applicationContext(cls, commandLine, environments);
Class<?> targetCommand = commandLine.getCommandSpec().userObject().getClass();
if (!AbstractCommand.class.isAssignableFrom(targetCommand) && args.length == 0) {
// if no command provided, show help
args = new String[]{"--help"};
}
// Call Picocli command
int exitCode = 0;
int exitCode;
try {
exitCode = new CommandLine(cls, new MicronautFactory(applicationContext)).execute(args);
} catch (CommandLine.InitializationException e){
@@ -77,7 +100,23 @@ public class App implements Callable<Integer> {
applicationContext.close();
// exit code
System.exit(Objects.requireNonNullElse(exitCode, 0));
return exitCode;
}
private static CommandLine getCommandLine(Class<?> cls, String[] args) {
CommandLine cmd = new CommandLine(cls, CommandLine.defaultFactory());
continueOnParsingErrors(cmd);
CommandLine.ParseResult parseResult = cmd.parseArgs(args);
List<CommandLine> parsedCommands = parseResult.asCommandLineList();
return parsedCommands.getLast();
}
public static ApplicationContext applicationContext(Class<?> mainClass,
String[] environments,
String... args) {
return App.applicationContext(mainClass, getCommandLine(mainClass, args), environments);
}
@@ -85,25 +124,17 @@ public class App implements Callable<Integer> {
* Create an {@link ApplicationContext} with additional properties based on configuration files (--config) and
* forced Properties from current command.
*
* @param args args passed to java app
* @return the application context created
*/
protected static ApplicationContext applicationContext(Class<?> mainClass,
String[] environments,
String[] args) {
CommandLine commandLine,
String[] environments) {
ApplicationContextBuilder builder = ApplicationContext
.builder()
.mainClass(mainClass)
.environments(environments);
CommandLine cmd = new CommandLine(mainClass, CommandLine.defaultFactory());
continueOnParsingErrors(cmd);
CommandLine.ParseResult parseResult = cmd.parseArgs(args);
List<CommandLine> parsedCommands = parseResult.asCommandLineList();
CommandLine commandLine = parsedCommands.getLast();
Class<?> cls = commandLine.getCommandSpec().userObject().getClass();
if (AbstractCommand.class.isAssignableFrom(cls)) {

View File

@@ -1,6 +1,5 @@
package io.kestra.cli.commands.configs.sys;
import io.micronaut.configuration.picocli.PicocliRunner;
import lombok.extern.slf4j.Slf4j;
import io.kestra.cli.AbstractCommand;
import io.kestra.cli.App;
@@ -20,8 +19,6 @@ public class ConfigCommand extends AbstractCommand {
public Integer call() throws Exception {
super.call();
PicocliRunner.call(App.class, "configs", "--help");
return 0;
return App.runCli(new String[]{"configs", "--help"});
}
}

View File

@@ -1,6 +1,5 @@
package io.kestra.cli.commands.flows;
import io.micronaut.configuration.picocli.PicocliRunner;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import io.kestra.cli.AbstractCommand;
@@ -29,8 +28,6 @@ public class FlowCommand extends AbstractCommand {
public Integer call() throws Exception {
super.call();
PicocliRunner.call(App.class, "flow", "--help");
return 0;
return App.runCli(new String[]{"flow", "--help"});
}
}

View File

@@ -1,7 +1,6 @@
package io.kestra.cli.commands.flows.namespaces;
import io.kestra.cli.App;
import io.micronaut.configuration.picocli.PicocliRunner;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import io.kestra.cli.AbstractCommand;
@@ -22,8 +21,6 @@ public class FlowNamespaceCommand extends AbstractCommand {
public Integer call() throws Exception {
super.call();
PicocliRunner.call(App.class, "flow", "namespace", "--help");
return 0;
return App.runCli(new String[]{"flow", "namespace", "--help"});
}
}

View File

@@ -3,7 +3,6 @@ package io.kestra.cli.commands.migrations;
import io.kestra.cli.AbstractCommand;
import io.kestra.cli.App;
import io.kestra.cli.commands.migrations.metadata.MetadataMigrationCommand;
import io.micronaut.configuration.picocli.PicocliRunner;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import picocli.CommandLine;
@@ -24,8 +23,6 @@ public class MigrationCommand extends AbstractCommand {
public Integer call() throws Exception {
super.call();
PicocliRunner.call(App.class, "migrate", "--help");
return 0;
return App.runCli(new String[]{"migrate", "--help"});
}
}

View File

@@ -4,7 +4,6 @@ import io.kestra.cli.AbstractCommand;
import io.kestra.cli.App;
import io.kestra.cli.commands.namespaces.files.NamespaceFilesCommand;
import io.kestra.cli.commands.namespaces.kv.KvCommand;
import io.micronaut.configuration.picocli.PicocliRunner;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import picocli.CommandLine;
@@ -25,8 +24,6 @@ public class NamespaceCommand extends AbstractCommand {
public Integer call() throws Exception {
super.call();
PicocliRunner.call(App.class, "namespace", "--help");
return 0;
return App.runCli(new String[]{"namespace", "--help"});
}
}

View File

@@ -2,7 +2,6 @@ package io.kestra.cli.commands.namespaces.files;
import io.kestra.cli.AbstractCommand;
import io.kestra.cli.App;
import io.micronaut.configuration.picocli.PicocliRunner;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import picocli.CommandLine;
@@ -22,8 +21,6 @@ public class NamespaceFilesCommand extends AbstractCommand {
public Integer call() throws Exception {
super.call();
PicocliRunner.call(App.class, "namespace", "files", "--help");
return 0;
return App.runCli(new String[]{"namespace", "files", "--help"});
}
}

View File

@@ -2,7 +2,6 @@ package io.kestra.cli.commands.namespaces.kv;
import io.kestra.cli.AbstractCommand;
import io.kestra.cli.App;
import io.micronaut.configuration.picocli.PicocliRunner;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import picocli.CommandLine;
@@ -22,8 +21,6 @@ public class KvCommand extends AbstractCommand {
public Integer call() throws Exception {
super.call();
PicocliRunner.call(App.class, "namespace", "kv", "--help");
return 0;
return App.runCli(new String[]{"namespace", "kv", "--help"});
}
}

View File

@@ -2,7 +2,6 @@ package io.kestra.cli.commands.plugins;
import io.kestra.cli.AbstractCommand;
import io.kestra.cli.App;
import io.micronaut.configuration.picocli.PicocliRunner;
import lombok.SneakyThrows;
import picocli.CommandLine.Command;
@@ -25,9 +24,7 @@ public class PluginCommand extends AbstractCommand {
public Integer call() throws Exception {
super.call();
PicocliRunner.call(App.class, "plugins", "--help");
return 0;
return App.runCli(new String[]{"plugins", "--help"});
}
@Override

View File

@@ -1,6 +1,5 @@
package io.kestra.cli.commands.servers;
import io.micronaut.configuration.picocli.PicocliRunner;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import io.kestra.cli.AbstractCommand;
@@ -28,8 +27,6 @@ public class ServerCommand extends AbstractCommand {
public Integer call() throws Exception {
super.call();
PicocliRunner.call(App.class, "server", "--help");
return 0;
return App.runCli(new String[]{"server", "--help"});
}
}

View File

@@ -2,7 +2,6 @@ package io.kestra.cli.commands.sys;
import io.kestra.cli.commands.sys.database.DatabaseCommand;
import io.kestra.cli.commands.sys.statestore.StateStoreCommand;
import io.micronaut.configuration.picocli.PicocliRunner;
import lombok.extern.slf4j.Slf4j;
import io.kestra.cli.AbstractCommand;
import io.kestra.cli.App;
@@ -25,8 +24,6 @@ public class SysCommand extends AbstractCommand {
public Integer call() throws Exception {
super.call();
PicocliRunner.call(App.class, "sys", "--help");
return 0;
return App.runCli(new String[]{"sys", "--help"});
}
}

View File

@@ -2,7 +2,6 @@ package io.kestra.cli.commands.sys.database;
import io.kestra.cli.AbstractCommand;
import io.kestra.cli.App;
import io.micronaut.configuration.picocli.PicocliRunner;
import lombok.SneakyThrows;
import picocli.CommandLine;
@@ -20,8 +19,6 @@ public class DatabaseCommand extends AbstractCommand {
public Integer call() throws Exception {
super.call();
PicocliRunner.call(App.class, "sys", "database", "--help");
return 0;
return App.runCli(new String[]{"sys", "database", "--help"});
}
}

View File

@@ -2,7 +2,6 @@ package io.kestra.cli.commands.sys.statestore;
import io.kestra.cli.AbstractCommand;
import io.kestra.cli.App;
import io.micronaut.configuration.picocli.PicocliRunner;
import lombok.SneakyThrows;
import picocli.CommandLine;
@@ -20,8 +19,6 @@ public class StateStoreCommand extends AbstractCommand {
public Integer call() throws Exception {
super.call();
PicocliRunner.call(App.class, "sys", "state-store", "--help");
return 0;
return App.runCli(new String[]{"sys", "state-store", "--help"});
}
}

View File

@@ -4,7 +4,6 @@ import io.kestra.cli.AbstractCommand;
import io.kestra.cli.App;
import io.kestra.cli.commands.templates.namespaces.TemplateNamespaceCommand;
import io.kestra.core.models.templates.TemplateEnabled;
import io.micronaut.configuration.picocli.PicocliRunner;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import picocli.CommandLine;
@@ -27,8 +26,6 @@ public class TemplateCommand extends AbstractCommand {
public Integer call() throws Exception {
super.call();
PicocliRunner.call(App.class, "template", "--help");
return 0;
return App.runCli(new String[]{"template", "--help"});
}
}

View File

@@ -3,7 +3,6 @@ package io.kestra.cli.commands.templates.namespaces;
import io.kestra.cli.AbstractCommand;
import io.kestra.cli.App;
import io.kestra.core.models.templates.TemplateEnabled;
import io.micronaut.configuration.picocli.PicocliRunner;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import picocli.CommandLine;
@@ -24,8 +23,6 @@ public class TemplateNamespaceCommand extends AbstractCommand {
public Integer call() throws Exception {
super.call();
PicocliRunner.call(App.class, "template", "namespace", "--help");
return 0;
return App.runCli(new String[]{"template", "namespace", "--help"});
}
}

View File

@@ -0,0 +1,16 @@
package io.kestra.cli.services;
import io.micronaut.context.env.Environment;
import java.util.Arrays;
import java.util.stream.Stream;
public class DefaultEnvironmentProvider implements EnvironmentProvider {
@Override
public String[] getCliEnvironments(String... extraEnvironments) {
return Stream.concat(
Stream.of(Environment.CLI),
Arrays.stream(extraEnvironments)
).toArray(String[]::new);
}
}

View File

@@ -0,0 +1,5 @@
package io.kestra.cli.services;
public interface EnvironmentProvider {
String[] getCliEnvironments(String... extraEnvironments);
}

View File

@@ -0,0 +1 @@
io.kestra.cli.services.DefaultEnvironmentProvider

View File

@@ -1,14 +1,11 @@
package io.kestra.cli;
import io.kestra.core.models.ServerType;
import io.micronaut.configuration.picocli.MicronautFactory;
import io.micronaut.configuration.picocli.PicocliRunner;
import io.micronaut.context.ApplicationContext;
import io.micronaut.context.env.Environment;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import picocli.CommandLine;
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
@@ -22,11 +19,15 @@ class AppTest {
ByteArrayOutputStream out = new ByteArrayOutputStream();
System.setOut(new PrintStream(out));
try (ApplicationContext ctx = ApplicationContext.run(Environment.CLI, Environment.TEST)) {
PicocliRunner.call(App.class, ctx, "--help");
// No arg will print help
assertThat(App.runCli(new String[0])).isZero();
assertThat(out.toString()).contains("kestra");
assertThat(out.toString()).contains("kestra");
}
out.reset();
// Explicit help command
assertThat(App.runCli(new String[]{"--help"})).isZero();
assertThat(out.toString()).contains("kestra");
}
@ParameterizedTest
@@ -38,11 +39,12 @@ class AppTest {
final String[] args = new String[]{"server", serverType, "--help"};
try (ApplicationContext ctx = App.applicationContext(App.class, new String [] { Environment.CLI }, args)) {
new CommandLine(App.class, new MicronautFactory(ctx)).execute(args);
assertTrue(ctx.getProperty("kestra.server-type", ServerType.class).isEmpty());
assertThat(out.toString()).startsWith("Usage: kestra server " + serverType);
}
assertThat(App.runCli(args)).isZero();
assertThat(out.toString()).startsWith("Usage: kestra server " + serverType);
}
@Test
@@ -52,12 +54,10 @@ class AppTest {
final String[] argsWithMissingParams = new String[]{"flow", "namespace", "update"};
try (ApplicationContext ctx = App.applicationContext(App.class, new String [] { Environment.CLI }, argsWithMissingParams)) {
new CommandLine(App.class, new MicronautFactory(ctx)).execute(argsWithMissingParams);
assertThat(App.runCli(argsWithMissingParams)).isEqualTo(2);
assertThat(out.toString()).startsWith("Missing required parameters: ");
assertThat(out.toString()).contains("Usage: kestra flow namespace update ");
assertThat(out.toString()).doesNotContain("MissingParameterException: ");
}
assertThat(out.toString()).startsWith("Missing required parameters: ");
assertThat(out.toString()).contains("Usage: kestra flow namespace update ");
assertThat(out.toString()).doesNotContain("MissingParameterException: ");
}
}

View File

@@ -21,6 +21,7 @@ kestra:
server:
liveness:
enabled: false
termination-grace-period: 5s
micronaut:
http:
services:

View File

@@ -3,7 +3,6 @@ package io.kestra.core.models.conditions;
import io.kestra.core.models.flows.FlowInterface;
import lombok.*;
import io.kestra.core.models.executions.Execution;
import io.kestra.core.models.flows.Flow;
import io.kestra.core.models.triggers.multipleflows.MultipleConditionStorageInterface;
import io.kestra.core.runners.RunContext;

View File

@@ -3,7 +3,7 @@ package io.kestra.core.models.executions;
import com.fasterxml.jackson.annotation.JsonInclude;
import io.kestra.core.models.DeletedInterface;
import io.kestra.core.models.TenantInterface;
import io.kestra.core.models.flows.Flow;
import io.kestra.core.models.flows.FlowInterface;
import io.kestra.core.models.triggers.AbstractTrigger;
import io.kestra.core.models.triggers.TriggerContext;
import io.swagger.v3.oas.annotations.Hidden;
@@ -97,7 +97,7 @@ public class LogEntry implements DeletedInterface, TenantInterface {
.build();
}
public static LogEntry of(Flow flow, AbstractTrigger abstractTrigger, ExecutionKind executionKind) {
public static LogEntry of(FlowInterface flow, AbstractTrigger abstractTrigger) {
return LogEntry.builder()
.tenantId(flow.getTenantId())
.namespace(flow.getNamespace())
@@ -107,7 +107,7 @@ public class LogEntry implements DeletedInterface, TenantInterface {
.build();
}
public static LogEntry of(TriggerContext triggerContext, AbstractTrigger abstractTrigger, ExecutionKind executionKind) {
public static LogEntry of(TriggerContext triggerContext, AbstractTrigger abstractTrigger) {
return LogEntry.builder()
.tenantId(triggerContext.getTenantId())
.namespace(triggerContext.getNamespace())

View File

@@ -48,7 +48,7 @@ public class SubflowGraphTask extends AbstractGraphTask {
public record SubflowTaskWrapper<T extends Output>(RunContext runContext, ExecutableTask<T> subflowTask) implements TaskInterface, ExecutableTask<T> {
@Override
public List<SubflowExecution<?>> createSubflowExecutions(RunContext runContext, FlowMetaStoreInterface flowExecutorInterface, Flow currentFlow, Execution currentExecution, TaskRun currentTaskRun) throws InternalException {
public List<SubflowExecution<?>> createSubflowExecutions(RunContext runContext, FlowMetaStoreInterface flowExecutorInterface, FlowInterface currentFlow, Execution currentExecution, TaskRun currentTaskRun) throws InternalException {
return subflowTask.createSubflowExecutions(runContext, flowExecutorInterface, currentFlow, currentExecution, currentTaskRun);
}

View File

@@ -24,7 +24,7 @@ public interface ExecutableTask<T extends Output>{
*/
List<SubflowExecution<?>> createSubflowExecutions(RunContext runContext,
FlowMetaStoreInterface flowExecutorInterface,
Flow currentFlow, Execution currentExecution,
FlowInterface currentFlow, Execution currentExecution,
TaskRun currentTaskRun) throws InternalException;
/**

View File

@@ -74,7 +74,7 @@ public class Trigger extends TriggerContext implements HasUID {
);
}
public static String uid(Flow flow, AbstractTrigger abstractTrigger) {
public static String uid(FlowInterface flow, AbstractTrigger abstractTrigger) {
return IdUtils.fromParts(
flow.getTenantId(),
flow.getNamespace(),

View File

@@ -2,14 +2,12 @@ package io.kestra.core.models.triggers.multipleflows;
import com.fasterxml.jackson.annotation.JsonIgnore;
import io.kestra.core.models.HasUID;
import io.kestra.core.models.flows.Flow;
import io.kestra.core.models.flows.FlowId;
import io.kestra.core.utils.IdUtils;
import lombok.Builder;
import lombok.Value;
import java.time.ZonedDateTime;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

View File

@@ -23,12 +23,12 @@ import java.util.Objects;
@Singleton
public class FeatureUsageReport extends AbstractReportable<FeatureUsageReport.UsageEvent> {
private final FlowRepositoryInterface flowRepository;
private final ExecutionRepositoryInterface executionRepository;
private final DashboardRepositoryInterface dashboardRepository;
private final boolean enabled;
@Inject
public FeatureUsageReport(FlowRepositoryInterface flowRepository,
ExecutionRepositoryInterface executionRepository,
@@ -37,26 +37,26 @@ public class FeatureUsageReport extends AbstractReportable<FeatureUsageReport.Us
this.flowRepository = flowRepository;
this.executionRepository = executionRepository;
this.dashboardRepository = dashboardRepository;
ServerType serverType = KestraContext.getContext().getServerType();
this.enabled = ServerType.EXECUTOR.equals(serverType) || ServerType.STANDALONE.equals(serverType);
}
@Override
public UsageEvent report(final Instant now, TimeInterval interval) {
return UsageEvent
.builder()
.flows(FlowUsage.of(flowRepository))
.executions(ExecutionUsage.of(executionRepository, interval.from(), interval.to()))
.dashboards(new Count(dashboardRepository.count()))
.dashboards(new Count(dashboardRepository.countAllForAllTenants()))
.build();
}
@Override
public boolean isEnabled() {
return enabled;
}
@Override
public UsageEvent report(Instant now, TimeInterval interval, String tenant) {
Objects.requireNonNull(tenant, "tenant is null");
@@ -67,7 +67,7 @@ public class FeatureUsageReport extends AbstractReportable<FeatureUsageReport.Us
.executions(ExecutionUsage.of(tenant, executionRepository, interval.from(), interval.to()))
.build();
}
@SuperBuilder(toBuilder = true)
@Getter
@Jacksonized

View File

@@ -16,14 +16,14 @@ import java.util.Map;
import java.util.Optional;
public interface DashboardRepositoryInterface {
/**
* Gets the total number of Dashboards.
*
* @return the total number.
*/
long count();
long countAllForAllTenants();
Boolean isEnabled();
Optional<Dashboard> get(String tenantId, String id);

View File

@@ -39,7 +39,7 @@ public interface TriggerRepositoryInterface extends QueryBuilderInterface<Trigge
* @param tenantId the tenant of the triggers
* @return The count.
*/
int count(@Nullable String tenantId);
long countAll(@Nullable String tenantId);
/**
* Find all triggers that match the query, return a flux of triggers

View File

@@ -26,7 +26,6 @@ import org.apache.commons.lang3.stream.Streams;
import java.time.Instant;
import java.time.ZonedDateTime;
import java.util.*;
import java.util.stream.Collectors;
import static io.kestra.core.trace.Tracer.throwCallable;
import static io.kestra.core.utils.Rethrow.throwConsumer;
@@ -67,7 +66,7 @@ public final class ExecutableUtils {
RunContext runContext,
FlowMetaStoreInterface flowExecutorInterface,
Execution currentExecution,
Flow currentFlow,
FlowInterface currentFlow,
T currentTask,
TaskRun currentTaskRun,
Map<String, Object> inputs,

View File

@@ -7,7 +7,6 @@ import io.kestra.core.exceptions.KestraRuntimeException;
import io.kestra.core.models.executions.Execution;
import io.kestra.core.models.flows.Data;
import io.kestra.core.models.flows.DependsOn;
import io.kestra.core.models.flows.Flow;
import io.kestra.core.models.flows.FlowInterface;
import io.kestra.core.models.flows.Input;
import io.kestra.core.models.flows.Output;
@@ -64,11 +63,11 @@ import static io.kestra.core.utils.Rethrow.throwFunction;
public class FlowInputOutput {
private static final Pattern URI_PATTERN = Pattern.compile("^[a-z]+:\\/\\/(?:www\\.)?[-a-zA-Z0-9@:%._\\+~#=]{1,256}\\.[a-zA-Z0-9()]{1,6}\\b(?:[-a-zA-Z0-9()@:%_\\+.~#?&\\/=]*)$");
private static final ObjectMapper YAML_MAPPER = JacksonMapper.ofYaml();
private final StorageInterface storageInterface;
private final Optional<String> secretKey;
private final RunContextFactory runContextFactory;
@Inject
public FlowInputOutput(
StorageInterface storageInterface,
@@ -79,7 +78,7 @@ public class FlowInputOutput {
this.runContextFactory = runContextFactory;
this.secretKey = Optional.ofNullable(secretKey);
}
/**
* Validate all the inputs of a given execution of a flow.
*
@@ -89,15 +88,15 @@ public class FlowInputOutput {
* @return The list of {@link InputAndValue}.
*/
public Mono<List<InputAndValue>> validateExecutionInputs(final List<Input<?>> inputs,
final Flow flow,
final FlowInterface flow,
final Execution execution,
final Publisher<CompletedPart> data) {
if (ListUtils.isEmpty(inputs)) return Mono.just(Collections.emptyList());
return readData(inputs, execution, data, false)
.map(inputData -> resolveInputs(inputs, flow, execution, inputData, false));
}
/**
* Reads all the inputs of a given execution of a flow.
*
@@ -111,7 +110,7 @@ public class FlowInputOutput {
final Publisher<CompletedPart> data) {
return this.readExecutionInputs(flow.getInputs(), flow, execution, data);
}
/**
* Reads all the inputs of a given execution of a flow.
*
@@ -126,7 +125,7 @@ public class FlowInputOutput {
final Publisher<CompletedPart> data) {
return readData(inputs, execution, data, true).map(inputData -> this.readExecutionInputs(inputs, flow, execution, inputData));
}
private Mono<Map<String, Object>> readData(List<Input<?>> inputs, Execution execution, Publisher<CompletedPart> data, boolean uploadFiles) {
return Flux.from(data)
.publishOn(Schedulers.boundedElastic())
@@ -235,7 +234,7 @@ public class FlowInputOutput {
}
return MapUtils.flattenToNestedMap(resolved);
}
/**
* Utility method for retrieving types inputs.
*
@@ -252,7 +251,7 @@ public class FlowInputOutput {
) {
return resolveInputs(inputs, flow, execution, data, true);
}
public List<InputAndValue> resolveInputs(
final List<Input<?>> inputs,
final FlowInterface flow,
@@ -325,7 +324,7 @@ public class FlowInputOutput {
}
});
resolvable.setInput(input);
Object value = resolvable.get().value();
// resolve default if needed

View File

@@ -6,7 +6,6 @@ import com.google.common.annotations.VisibleForTesting;
import io.kestra.core.metrics.MetricRegistry;
import io.kestra.core.models.executions.Execution;
import io.kestra.core.models.executions.TaskRun;
import io.kestra.core.models.flows.Flow;
import io.kestra.core.models.flows.FlowInterface;
import io.kestra.core.models.flows.Type;
import io.kestra.core.models.property.PropertyContext;
@@ -41,7 +40,7 @@ public class RunContextFactory {
@Inject
protected VariableRenderer variableRenderer;
@Inject
protected SecureVariableRendererFactory secureVariableRendererFactory;
@@ -81,11 +80,11 @@ public class RunContextFactory {
public RunContextInitializer initializer() {
return applicationContext.getBean(RunContextInitializer.class);
}
public RunContext of(FlowInterface flow, Execution execution) {
return of(flow, execution, Function.identity());
}
public RunContext of(FlowInterface flow, Execution execution, boolean decryptVariable) {
return of(flow, execution, Function.identity(), decryptVariable);
}
@@ -93,12 +92,12 @@ public class RunContextFactory {
public RunContext of(FlowInterface flow, Execution execution, Function<RunVariables.Builder, RunVariables.Builder> runVariableModifier) {
return of(flow, execution, runVariableModifier, true);
}
public RunContext of(FlowInterface flow, Execution execution, Function<RunVariables.Builder, RunVariables.Builder> runVariableModifier, boolean decryptVariables) {
RunContextLogger runContextLogger = runContextLoggerFactory.create(execution);
VariableRenderer variableRenderer = decryptVariables ? this.variableRenderer : secureVariableRendererFactory.createOrGet();
return newBuilder()
// Logger
.withLogger(runContextLogger)
@@ -150,8 +149,8 @@ public class RunContextFactory {
.build();
}
public RunContext of(Flow flow, AbstractTrigger trigger) {
RunContextLogger runContextLogger = runContextLoggerFactory.create(flow, trigger, null);
public RunContext of(FlowInterface flow, AbstractTrigger trigger) {
RunContextLogger runContextLogger = runContextLoggerFactory.create(flow, trigger);
return newBuilder()
// Logger
.withLogger(runContextLogger)
@@ -170,7 +169,7 @@ public class RunContextFactory {
@VisibleForTesting
public RunContext of(final Flow flow, final Map<String, Object> variables) {
public RunContext of(final FlowInterface flow, final Map<String, Object> variables) {
RunContextLogger runContextLogger = new RunContextLogger();
return newBuilder()
.withLogger(runContextLogger)

View File

@@ -213,7 +213,7 @@ public class RunContextInitializer {
runContext.init(applicationContext);
final String triggerExecutionId = IdUtils.create();
final RunContextLogger runContextLogger = contextLoggerFactory.create(triggerContext, trigger, null);
final RunContextLogger runContextLogger = contextLoggerFactory.create(triggerContext, trigger);
final Map<String, Object> variables = new HashMap<>(runContext.getVariables());
variables.put(RunVariables.SECRET_CONSUMER_VARIABLE_NAME, (Consumer<String>) runContextLogger::usedSecret);

View File

@@ -4,7 +4,7 @@ import io.kestra.core.models.executions.Execution;
import io.kestra.core.models.executions.ExecutionKind;
import io.kestra.core.models.executions.LogEntry;
import io.kestra.core.models.executions.TaskRun;
import io.kestra.core.models.flows.Flow;
import io.kestra.core.models.flows.FlowInterface;
import io.kestra.core.models.tasks.Task;
import io.kestra.core.models.triggers.AbstractTrigger;
import io.kestra.core.models.triggers.TriggerContext;
@@ -46,19 +46,19 @@ public class RunContextLoggerFactory {
);
}
public RunContextLogger create(TriggerContext triggerContext, AbstractTrigger trigger, ExecutionKind executionKind) {
public RunContextLogger create(TriggerContext triggerContext, AbstractTrigger trigger) {
return new RunContextLogger(
logQueue,
LogEntry.of(triggerContext, trigger, executionKind),
LogEntry.of(triggerContext, trigger),
trigger.getLogLevel(),
trigger.isLogToFile()
);
}
public RunContextLogger create(Flow flow, AbstractTrigger trigger, ExecutionKind executionKind) {
public RunContextLogger create(FlowInterface flow, AbstractTrigger trigger) {
return new RunContextLogger(
logQueue,
LogEntry.of(flow, trigger, executionKind),
LogEntry.of(flow, trigger),
trigger.getLogLevel(),
trigger.isLogToFile()
);

View File

@@ -5,8 +5,8 @@ import io.kestra.core.exceptions.IllegalVariableEvaluationException;
import io.kestra.core.models.Label;
import io.kestra.core.models.executions.Execution;
import io.kestra.core.models.executions.TaskRun;
import io.kestra.core.models.flows.Flow;
import io.kestra.core.models.flows.FlowInterface;
import io.kestra.core.models.flows.GenericFlow;
import io.kestra.core.models.flows.Input;
import io.kestra.core.models.flows.State;
import io.kestra.core.models.flows.input.SecretInput;
@@ -73,7 +73,7 @@ public final class RunVariables {
}
/**
* Creates an immutable map representation of the given {@link Flow}.
* Creates an immutable map representation of the given {@link FlowInterface}.
*
* @param flow The flow from which to create variables.
* @return a new immutable {@link Map}.
@@ -283,7 +283,7 @@ public final class RunVariables {
if (flow != null && flow.getInputs() != null) {
// Create a new PropertyContext with 'flow' variables which are required by some pebble expressions.
PropertyContextWithVariables context = new PropertyContextWithVariables(propertyContext, Map.of("flow", RunVariables.of(flow)));
// we add default inputs value from the flow if not already set, this will be useful for triggers
flow.getInputs().stream()
.filter(input -> input.getDefaults() != null && !inputs.containsKey(input.getId()))
@@ -326,7 +326,7 @@ public final class RunVariables {
}
if (flow == null) {
Flow flowFromExecution = Flow.builder()
FlowInterface flowFromExecution = GenericFlow.builder()
.id(execution.getFlowId())
.tenantId(execution.getTenantId())
.revision(execution.getFlowRevision())
@@ -393,17 +393,17 @@ public final class RunVariables {
}
private RunVariables(){}
private record PropertyContextWithVariables(
PropertyContext delegate,
Map<String, Object> variables
) implements PropertyContext {
@Override
public String render(String inline, Map<String, Object> variables) throws IllegalVariableEvaluationException {
return delegate.render(inline, variables.isEmpty() ? this.variables : variables);
}
@Override
public Map<String, Object> render(Map<String, Object> inline, Map<String, Object> variables) throws IllegalVariableEvaluationException {
return delegate.render(inline, variables.isEmpty() ? this.variables : variables);

View File

@@ -1,7 +1,6 @@
package io.kestra.core.runners;
import io.kestra.core.models.conditions.ConditionContext;
import io.kestra.core.models.flows.Flow;
import io.kestra.core.models.flows.FlowWithSource;
import io.kestra.core.models.triggers.AbstractTrigger;
import io.kestra.core.models.triggers.Trigger;
@@ -28,7 +27,7 @@ public interface SchedulerTriggerStateInterface {
Trigger update(Trigger trigger);
Trigger update(Flow flow, AbstractTrigger abstractTrigger, ConditionContext conditionContext) throws Exception;
Trigger update(FlowWithSource flow, AbstractTrigger abstractTrigger, ConditionContext conditionContext) throws Exception;
/**
* QueueException required for Kafka implementation

View File

@@ -3,7 +3,6 @@ package io.kestra.core.storages;
import com.google.common.annotations.VisibleForTesting;
import io.kestra.core.models.executions.Execution;
import io.kestra.core.models.executions.TaskRun;
import io.kestra.core.models.flows.Flow;
import io.kestra.core.models.flows.FlowId;
import io.kestra.core.utils.Hashing;
import io.kestra.core.utils.Slugify;
@@ -62,9 +61,9 @@ public class StorageContext {
taskRun.getValue()
);
}
/**
* Factory method for constructing a new {@link StorageContext} scoped to a given {@link Flow}.
* Factory method for constructing a new {@link StorageContext} scoped to a given {@link FlowId}.
*/
public static StorageContext forFlow(FlowId flow) {
return new StorageContext(flow.getTenantId(), flow.getNamespace(), flow.getId());
@@ -227,7 +226,7 @@ public class StorageContext {
}
/**
* Gets the base storage URI for the current {@link io.kestra.core.models.flows.Flow}.
* Gets the base storage URI for the current {@link FlowId}.
*
* @return the {@link URI}.
*/

View File

@@ -1,9 +1,9 @@
package io.kestra.core.utils;
import io.kestra.core.models.flows.FlowInterface;
import io.micronaut.context.annotation.Value;
import org.apache.commons.lang3.StringUtils;
import io.kestra.core.models.executions.Execution;
import io.kestra.core.models.flows.Flow;
import java.net.URI;
import io.micronaut.core.annotation.Nullable;
@@ -44,7 +44,7 @@ public class UriProvider {
execution.getFlowId());
}
public URI flowUrl(Flow flow) {
public URI flowUrl(FlowInterface flow) {
return this.build("/ui/" +
(flow.getTenantId() != null ? flow.getTenantId() + "/" : "") +
"flows/" +

View File

@@ -44,33 +44,15 @@ import java.util.Optional;
"""
),
@Example(
full = true,
code = """
id: return
namespace: company.team
inputs:
- id: token
type: STRING
displayName: "API Token"
- id: username
type: STRING
displayName: "Username"
- id: password
type: STRING
displayName: "Password"
tasks:
- id: compute_header
type: io.kestra.plugin.core.debug.Return
format: >-
{%- if inputs.token is not empty -%}
Bearer {{ inputs.token }}
{%- elseif inputs.username is not empty and inputs.password is not empty -%}
Basic {{ (inputs.username + ':' + inputs.password) | base64encode }}
{%- endif -%}
id: compute_header
type: io.kestra.plugin.core.debug.Return
format: >-
{%- if inputs.token is not empty -%}
Bearer {{ inputs.token }}
{%- elseif inputs.username is not empty and inputs.password is not empty -%}
Basic {{ (inputs.username + ':' + inputs.password) | base64encode }}
{%- endif -%}
"""
)
},

View File

@@ -10,7 +10,6 @@ import io.kestra.core.models.annotations.Example;
import io.kestra.core.models.annotations.Plugin;
import io.kestra.core.models.annotations.PluginProperty;
import io.kestra.core.models.executions.*;
import io.kestra.core.models.flows.Flow;
import io.kestra.core.models.flows.FlowInterface;
import io.kestra.core.models.flows.State;
import io.kestra.core.models.hierarchies.GraphCluster;
@@ -466,7 +465,7 @@ public class ForEachItem extends Task implements FlowableTask<VoidOutput>, Child
public List<SubflowExecution<?>> createSubflowExecutions(
RunContext runContext,
FlowMetaStoreInterface flowExecutorInterface,
Flow currentFlow,
FlowInterface currentFlow,
Execution currentExecution,
TaskRun currentTaskRun
) throws InternalException {

View File

@@ -174,7 +174,7 @@ public class Subflow extends Task implements ExecutableTask<Subflow.Output>, Chi
@Override
public List<SubflowExecution<?>> createSubflowExecutions(RunContext runContext,
FlowMetaStoreInterface flowExecutorInterface,
io.kestra.core.models.flows.Flow currentFlow,
FlowInterface currentFlow,
Execution currentExecution,
TaskRun currentTaskRun) throws InternalException {
Map<String, Object> inputs = new HashMap<>();

View File

@@ -4,6 +4,7 @@ import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.kestra.core.models.annotations.PluginProperty;
import io.kestra.core.models.flows.FlowInterface;
import io.kestra.core.validations.WebhookValidation;
import io.micronaut.http.HttpRequest;
import io.swagger.v3.oas.annotations.media.Schema;
@@ -156,8 +157,8 @@ public class Webhook extends AbstractTrigger implements TriggerOutput<Webhook.Ou
"""
)
private Boolean wait = false;
@Schema(
title = "The inputs to pass to the triggered flow"
)
@@ -172,7 +173,7 @@ public class Webhook extends AbstractTrigger implements TriggerOutput<Webhook.Ou
)
private Boolean returnOutputs = false;
public Optional<Execution> evaluate(HttpRequest<String> request, io.kestra.core.models.flows.Flow flow) {
public Optional<Execution> evaluate(HttpRequest<String> request, FlowInterface flow) {
String body = request.getBody().orElse(null);
Execution.ExecutionBuilder builder = Execution.builder()

View File

@@ -192,7 +192,7 @@ public abstract class AbstractTriggerRepositoryTest {
.build()
);
// When
int count = triggerRepository.count(tenant);
long count = triggerRepository.countAll(tenant);
// Then
assertThat(count).isEqualTo(1);
}

View File

@@ -58,7 +58,8 @@ kestra:
purge:
initial-delay: 1h
fixed-delay: 1d
retention: 30d
retention: 30dPeriod
termination-grace-period: 5s
anonymous-usage-report:
enabled: false

View File

@@ -4,7 +4,7 @@ namespace: io.kestra.tests
tasks:
- id: sleep-long
type: io.kestra.plugin.core.flow.Sleep
duration: PT300S
duration: PT30S
afterExecution:
- id: output

View File

@@ -17,7 +17,7 @@ services:
postgres:
image: postgres:18
volumes:
- postgres-data:/var/lib/postgresql/18/docker
- postgres-data:/var/lib/postgresql
environment:
POSTGRES_DB: kestra
POSTGRES_USER: kestra

View File

@@ -8,7 +8,7 @@ services:
postgres:
image: postgres:18
volumes:
- postgres-data:/var/lib/postgresql/18/docker
- postgres-data:/var/lib/postgresql
environment:
POSTGRES_DB: kestra
POSTGRES_USER: kestra

View File

@@ -5,8 +5,8 @@ import io.kestra.core.exceptions.InternalException;
import io.kestra.core.metrics.MetricRegistry;
import io.kestra.core.models.Label;
import io.kestra.core.models.executions.*;
import io.kestra.core.models.flows.Flow;
import io.kestra.core.models.flows.FlowInterface;
import io.kestra.core.models.flows.FlowWithSource;
import io.kestra.core.models.flows.State;
import io.kestra.core.models.flows.sla.Violation;
import io.kestra.core.models.tasks.*;
@@ -237,7 +237,7 @@ public class ExecutorService {
return newExecution;
}
private Optional<WorkerTaskResult> childWorkerTaskResult(Flow flow, Execution execution, TaskRun parentTaskRun) throws InternalException {
private Optional<WorkerTaskResult> childWorkerTaskResult(FlowWithSource flow, Execution execution, TaskRun parentTaskRun) throws InternalException {
Task parent = flow.findTaskByTaskId(parentTaskRun.getTaskId());
if (parent instanceof FlowableTask<?> flowableParent) {
@@ -393,7 +393,7 @@ public class ExecutorService {
}
private Executor onEnd(Executor executor) {
final Flow flow = executor.getFlow();
final FlowWithSource flow = executor.getFlow();
Execution newExecution = executor.getExecution()
.withState(executor.getExecution().guessFinalState(flow));
@@ -1134,7 +1134,7 @@ public class ExecutorService {
}
}
public void addWorkerTaskResult(Executor executor, Supplier<Flow> flow, WorkerTaskResult workerTaskResult) throws InternalException {
public void addWorkerTaskResult(Executor executor, Supplier<FlowWithSource> flow, WorkerTaskResult workerTaskResult) throws InternalException {
// dynamic tasks
Execution newExecution = this.addDynamicTaskRun(
executor.getExecution(),
@@ -1175,7 +1175,7 @@ public class ExecutorService {
}
// Note: as the flow is only used in an error branch and it can take time to load, we pass it thought a Supplier
private Execution addDynamicTaskRun(Execution execution, Supplier<Flow> flow, WorkerTaskResult workerTaskResult) throws InternalException {
private Execution addDynamicTaskRun(Execution execution, Supplier<FlowWithSource> flow, WorkerTaskResult workerTaskResult) throws InternalException {
ArrayList<TaskRun> taskRuns = new ArrayList<>(ListUtils.emptyOnNull(execution.getTaskRunList()));
// declared dynamic tasks

View File

@@ -1,7 +1,7 @@
package io.kestra.executor;
import io.kestra.core.models.executions.Execution;
import io.kestra.core.models.flows.Flow;
import io.kestra.core.models.flows.FlowInterface;
import io.kestra.core.models.flows.sla.ExecutionChangedSLA;
import io.kestra.core.models.flows.sla.SLA;
import io.kestra.core.models.flows.sla.Violation;
@@ -19,7 +19,7 @@ public class SLAService {
* Evaluate execution changed SLA of a flow for an execution.
* Each violated SLA will be logged.
*/
public List<Violation> evaluateExecutionChangedSLA(RunContext runContext, Flow flow, Execution execution) {
public List<Violation> evaluateExecutionChangedSLA(RunContext runContext, FlowInterface flow, Execution execution) {
return ListUtils.emptyOnNull(flow.getSla()).stream()
.filter(ExecutionChangedSLA.class::isInstance)
.map(

View File

@@ -54,6 +54,7 @@ kestra:
- "/api/v1/executions/webhook/"
liveness:
enabled: false
termination-grace-period: 5s
service:
purge:
initial-delay: 1h

View File

@@ -2,6 +2,7 @@ package io.kestra.repository.h2;
import io.kestra.core.events.CrudEvent;
import io.kestra.core.models.dashboards.Dashboard;
import io.kestra.core.queues.QueueService;
import io.kestra.core.repositories.QueryBuilderInterface;
import io.kestra.jdbc.repository.AbstractJdbcDashboardRepository;
import io.micronaut.context.event.ApplicationEventPublisher;
@@ -17,9 +18,10 @@ import java.util.List;
public class H2DashboardRepository extends AbstractJdbcDashboardRepository {
@Inject
public H2DashboardRepository(@Named("dashboards") H2Repository<Dashboard> repository,
QueueService queueService,
ApplicationEventPublisher<CrudEvent<Dashboard>> eventPublisher,
List<QueryBuilderInterface<?>> queryBuilders) {
super(repository, eventPublisher, queryBuilders);
super(repository, queueService, eventPublisher, queryBuilders);
}
@Override

View File

@@ -16,6 +16,6 @@ public abstract class H2DashboardRepositoryService {
conditions.add(jdbcRepository.fullTextCondition(List.of("fulltext"), query));
}
return conditions.isEmpty() ? DSL.trueCondition() : DSL.and(conditions);
return conditions.isEmpty() ? DSL.noCondition() : DSL.and(conditions);
}
}

View File

@@ -2,6 +2,7 @@ package io.kestra.repository.h2;
import io.kestra.core.models.QueryFilter;
import io.kestra.core.models.executions.Execution;
import io.kestra.core.queues.QueueService;
import io.kestra.core.utils.DateUtils;
import io.kestra.core.utils.Either;
import io.kestra.jdbc.repository.AbstractJdbcExecutionRepository;
@@ -22,10 +23,11 @@ import java.util.*;
public class H2ExecutionRepository extends AbstractJdbcExecutionRepository {
@Inject
public H2ExecutionRepository(@Named("executions") H2Repository<Execution> repository,
QueueService queueService,
ApplicationContext applicationContext,
AbstractJdbcExecutorStateStorage executorStateStorage,
JdbcFilterService filterService) {
super(repository, applicationContext, executorStateStorage, filterService);
super(repository, queueService, applicationContext, executorStateStorage, filterService);
}
@Override

View File

@@ -32,7 +32,7 @@ public abstract class H2ExecutionRepositoryService {
});
}
return conditions.isEmpty() ? DSL.trueCondition() : DSL.and(conditions);
return conditions.isEmpty() ? DSL.noCondition() : DSL.and(conditions);
}
public static Condition findLabelCondition(Either<Map<?, ?>, String> input, QueryFilter.Op operation) {
@@ -64,6 +64,6 @@ public abstract class H2ExecutionRepositoryService {
if (!inConditions.isEmpty()) {
conditions.add(DSL.or(inConditions));
}
return conditions.isEmpty() ? DSL.trueCondition() : DSL.and(conditions);
return conditions.isEmpty() ? DSL.noCondition() : DSL.and(conditions);
}
}

View File

@@ -31,7 +31,7 @@ public abstract class H2FlowRepositoryService {
});
}
return conditions.isEmpty() ? DSL.trueCondition() : DSL.and(conditions);
return conditions.isEmpty() ? DSL.noCondition() : DSL.and(conditions);
}
public static Condition findSourceCodeCondition(AbstractJdbcRepository<? extends FlowInterface> jdbcRepository, String query) {
@@ -54,6 +54,6 @@ public abstract class H2FlowRepositoryService {
});
}
return conditions.isEmpty() ? DSL.trueCondition() : DSL.and(conditions);
return conditions.isEmpty() ? DSL.noCondition() : DSL.and(conditions);
}
}

View File

@@ -1,27 +1,20 @@
package io.kestra.repository.h2;
import io.kestra.core.models.QueryFilter;
import io.kestra.core.models.kv.PersistedKvMetadata;
import io.kestra.core.queues.QueueService;
import io.kestra.jdbc.repository.AbstractJdbcKvMetadataRepository;
import io.kestra.jdbc.services.JdbcFilterService;
import io.micronaut.context.ApplicationContext;
import jakarta.inject.Inject;
import jakarta.inject.Named;
import jakarta.inject.Singleton;
import org.jooq.Condition;
import org.jooq.Field;
import org.jooq.impl.DSL;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@Singleton
@H2RepositoryEnabled
public class H2KvMetadataRepository extends AbstractJdbcKvMetadataRepository {
@Inject
public H2KvMetadataRepository(@Named("kvMetadata") H2Repository<PersistedKvMetadata> repository) {
super(repository);
public H2KvMetadataRepository(@Named("kvMetadata") H2Repository<PersistedKvMetadata> repository, QueueService queueService, ApplicationContext applicationContext) {
super(repository, queueService);
}

View File

@@ -16,6 +16,6 @@ public abstract class H2KvMetadataRepositoryService {
conditions.add(jdbcRepository.fullTextCondition(List.of("fulltext"), query));
}
return conditions.isEmpty() ? DSL.trueCondition() : DSL.and(conditions);
return conditions.isEmpty() ? DSL.noCondition() : DSL.and(conditions);
}
}

View File

@@ -1,6 +1,7 @@
package io.kestra.repository.h2;
import io.kestra.core.models.executions.LogEntry;
import io.kestra.core.queues.QueueService;
import io.kestra.core.utils.DateUtils;
import io.kestra.jdbc.repository.AbstractJdbcLogRepository;
import io.kestra.jdbc.services.JdbcFilterService;
@@ -19,8 +20,9 @@ import java.util.List;
public class H2LogRepository extends AbstractJdbcLogRepository {
@Inject
public H2LogRepository(@Named("logs") H2Repository<LogEntry> repository,
QueueService queueService,
JdbcFilterService filterService) {
super(repository, filterService);
super(repository, queueService, filterService);
}
@Override

View File

@@ -1,6 +1,7 @@
package io.kestra.repository.h2;
import io.kestra.core.models.executions.MetricEntry;
import io.kestra.core.queues.QueueService;
import io.kestra.core.utils.DateUtils;
import io.kestra.jdbc.repository.AbstractJdbcMetricRepository;
import io.kestra.jdbc.services.JdbcFilterService;
@@ -17,8 +18,9 @@ import java.util.Date;
public class H2MetricRepository extends AbstractJdbcMetricRepository {
@Inject
public H2MetricRepository(@Named("metrics") H2Repository<MetricEntry> repository,
QueueService queueService,
JdbcFilterService filterService) {
super(repository, filterService);
super(repository, queueService, filterService);
}
@Override

View File

@@ -76,7 +76,7 @@ public class H2Repository<T> extends io.kestra.jdbc.AbstractJdbcRepository<T> {
public Condition fullTextCondition(List<String> fields, String query) {
if (query == null || query.equals("*")) {
return DSL.trueCondition();
return DSL.noCondition();
}
if (fields.size() > 1) {
@@ -105,12 +105,12 @@ public class H2Repository<T> extends io.kestra.jdbc.AbstractJdbcRepository<T> {
.sort(select, pageable)
.asTable("page")
)
.where(DSL.trueCondition()),
.where(DSL.noCondition()),
pageable
)
.fetch();
Integer totalCount = results.size() > 0 ? results.getFirst().get("total_count", Integer.class) : 0;
Integer totalCount = !results.isEmpty() ? results.getFirst().get("total_count", Integer.class) : 0;
List<E> map = results
.map((Record record) -> mapper.map((R) record));

View File

@@ -1,6 +1,7 @@
package io.kestra.repository.h2;
import io.kestra.core.models.Setting;
import io.kestra.core.queues.QueueService;
import io.kestra.jdbc.repository.AbstractJdbcSettingRepository;
import io.micronaut.context.ApplicationContext;
import jakarta.inject.Inject;
@@ -12,7 +13,8 @@ import jakarta.inject.Singleton;
public class H2SettingRepository extends AbstractJdbcSettingRepository {
@Inject
public H2SettingRepository(@Named("settings") H2Repository<Setting> repository,
QueueService queueService,
ApplicationContext applicationContext) {
super(repository, applicationContext);
super(repository, queueService, applicationContext);
}
}

View File

@@ -2,6 +2,7 @@ package io.kestra.repository.h2;
import io.kestra.core.models.templates.Template;
import io.kestra.core.models.templates.TemplateEnabled;
import io.kestra.core.queues.QueueService;
import io.kestra.jdbc.repository.AbstractJdbcTemplateRepository;
import io.micronaut.context.ApplicationContext;
import jakarta.inject.Inject;
@@ -17,8 +18,9 @@ import java.util.List;
public class H2TemplateRepository extends AbstractJdbcTemplateRepository {
@Inject
public H2TemplateRepository(@Named("templates") H2Repository<Template> repository,
QueueService queueService,
ApplicationContext applicationContext) {
super(repository, applicationContext);
super(repository, queueService, applicationContext);
}
@Override

View File

@@ -1,6 +1,7 @@
package io.kestra.repository.h2;
import io.kestra.core.models.triggers.Trigger;
import io.kestra.core.queues.QueueService;
import io.kestra.core.utils.DateUtils;
import io.kestra.jdbc.repository.AbstractJdbcTriggerRepository;
import io.kestra.jdbc.services.JdbcFilterService;
@@ -17,8 +18,9 @@ import java.util.Date;
public class H2TriggerRepository extends AbstractJdbcTriggerRepository {
@Inject
public H2TriggerRepository(@Named("triggers") H2Repository<Trigger> repository,
QueueService queueService,
JdbcFilterService filterService) {
super(repository, filterService);
super(repository, queueService, filterService);
}
@Override

View File

@@ -19,6 +19,7 @@ kestra:
server:
liveness:
enabled: false
termination-grace-period: 5s
service:
purge:
initial-delay: 1h

View File

@@ -2,6 +2,7 @@ package io.kestra.repository.mysql;
import io.kestra.core.events.CrudEvent;
import io.kestra.core.models.dashboards.Dashboard;
import io.kestra.core.queues.QueueService;
import io.kestra.core.repositories.QueryBuilderInterface;
import io.kestra.jdbc.repository.AbstractJdbcDashboardRepository;
import io.micronaut.context.event.ApplicationEventPublisher;
@@ -17,9 +18,10 @@ import java.util.List;
public class MysqlDashboardRepository extends AbstractJdbcDashboardRepository {
@Inject
public MysqlDashboardRepository(@Named("dashboards") MysqlRepository<Dashboard> repository,
QueueService queueService,
ApplicationEventPublisher<CrudEvent<Dashboard>> eventPublisher,
List<QueryBuilderInterface<?>> queryBuilders) {
super(repository, eventPublisher, queryBuilders);
super(repository, queueService, eventPublisher, queryBuilders);
}
@Override

View File

@@ -17,6 +17,6 @@ public abstract class MysqlDashboardRepositoryService {
conditions.add(jdbcRepository.fullTextCondition(Arrays.asList("title"), query));
}
return conditions.isEmpty() ? DSL.trueCondition() : DSL.and(conditions);
return conditions.isEmpty() ? DSL.noCondition() : DSL.and(conditions);
}
}

View File

@@ -2,6 +2,7 @@ package io.kestra.repository.mysql;
import io.kestra.core.models.QueryFilter;
import io.kestra.core.models.executions.Execution;
import io.kestra.core.queues.QueueService;
import io.kestra.core.utils.DateUtils;
import io.kestra.core.utils.Either;
import io.kestra.jdbc.repository.AbstractJdbcExecutionRepository;
@@ -25,10 +26,11 @@ import static io.kestra.core.models.QueryFilter.Op.EQUALS;
public class MysqlExecutionRepository extends AbstractJdbcExecutionRepository {
@Inject
public MysqlExecutionRepository(@Named("executions") MysqlRepository<Execution> repository,
QueueService queueService,
ApplicationContext applicationContext,
AbstractJdbcExecutorStateStorage executorStateStorage,
JdbcFilterService filterService) {
super(repository, applicationContext, executorStateStorage, filterService);
super(repository, queueService, applicationContext, executorStateStorage, filterService);
}
@Override

View File

@@ -27,7 +27,7 @@ public abstract class MysqlExecutionRepositoryService {
});
}
return conditions.isEmpty() ? DSL.trueCondition() : DSL.and(conditions);
return conditions.isEmpty() ? DSL.noCondition() : DSL.and(conditions);
}
public static Condition findLabelCondition(Either<Map<?, ?>, String> input, QueryFilter.Op operation) {
@@ -63,7 +63,7 @@ public abstract class MysqlExecutionRepositoryService {
if(!inConditions.isEmpty()){
conditions.add(DSL.or(inConditions));
}
return conditions.isEmpty() ? DSL.trueCondition() : DSL.and(conditions);
return conditions.isEmpty() ? DSL.noCondition() : DSL.and(conditions);
}
}

View File

@@ -27,7 +27,7 @@ public abstract class MysqlFlowRepositoryService {
});
}
return conditions.isEmpty() ? DSL.trueCondition() : DSL.and(conditions);
return conditions.isEmpty() ? DSL.noCondition() : DSL.and(conditions);
}
public static Condition findSourceCodeCondition(AbstractJdbcRepository<? extends FlowInterface> jdbcRepository, String query) {
@@ -45,6 +45,6 @@ public abstract class MysqlFlowRepositoryService {
});
}
return conditions.isEmpty() ? DSL.trueCondition() : DSL.and(conditions);
return conditions.isEmpty() ? DSL.noCondition() : DSL.and(conditions);
}
}

View File

@@ -1,6 +1,7 @@
package io.kestra.repository.mysql;
import io.kestra.core.models.kv.PersistedKvMetadata;
import io.kestra.core.queues.QueueService;
import io.kestra.jdbc.repository.AbstractJdbcKvMetadataRepository;
import io.micronaut.context.ApplicationContext;
import jakarta.inject.Inject;
@@ -17,9 +18,10 @@ import java.util.List;
public class MysqlKvMetadataRepository extends AbstractJdbcKvMetadataRepository {
@Inject
public MysqlKvMetadataRepository(
@Named("kvMetadata") MysqlRepository<PersistedKvMetadata> repository
@Named("kvMetadata") MysqlRepository<PersistedKvMetadata> repository,
QueueService queueService
) {
super(repository);
super(repository, queueService);
}
@Override

View File

@@ -16,6 +16,6 @@ public abstract class MysqlKvMetadataRepositoryService {
conditions.add(jdbcRepository.fullTextCondition(List.of("name"), query));
}
return conditions.isEmpty() ? DSL.trueCondition() : DSL.and(conditions);
return conditions.isEmpty() ? DSL.noCondition() : DSL.and(conditions);
}
}

View File

@@ -1,6 +1,7 @@
package io.kestra.repository.mysql;
import io.kestra.core.models.executions.LogEntry;
import io.kestra.core.queues.QueueService;
import io.kestra.core.utils.DateUtils;
import io.kestra.jdbc.repository.AbstractJdbcLogRepository;
import io.kestra.jdbc.services.JdbcFilterService;
@@ -19,8 +20,9 @@ import java.util.Date;
public class MysqlLogRepository extends AbstractJdbcLogRepository {
@Inject
public MysqlLogRepository(@Named("logs") MysqlRepository<LogEntry> repository,
QueueService queueService,
JdbcFilterService filterService) {
super(repository, filterService);
super(repository, queueService, filterService);
}
@Override

View File

@@ -1,6 +1,7 @@
package io.kestra.repository.mysql;
import io.kestra.core.models.executions.MetricEntry;
import io.kestra.core.queues.QueueService;
import io.kestra.core.utils.DateUtils;
import io.kestra.jdbc.repository.AbstractJdbcMetricRepository;
import io.kestra.jdbc.services.JdbcFilterService;
@@ -18,8 +19,9 @@ import java.util.Date;
public class MysqlMetricRepository extends AbstractJdbcMetricRepository {
@Inject
public MysqlMetricRepository(@Named("metrics") MysqlRepository<MetricEntry> repository,
QueueService queueService,
JdbcFilterService filterService) {
super(repository, filterService);
super(repository, queueService, filterService);
}
@Override

View File

@@ -43,7 +43,7 @@ public class MysqlRepository<T> extends AbstractJdbcRepository<T> {
@Override
public Condition fullTextCondition(List<String> fields, String query) {
if (query == null || query.equals("*")) {
return DSL.trueCondition();
return DSL.noCondition();
}
String match = Arrays

View File

@@ -1,6 +1,7 @@
package io.kestra.repository.mysql;
import io.kestra.core.models.Setting;
import io.kestra.core.queues.QueueService;
import io.kestra.jdbc.repository.AbstractJdbcSettingRepository;
import io.micronaut.context.ApplicationContext;
import jakarta.inject.Inject;
@@ -12,7 +13,8 @@ import jakarta.inject.Singleton;
public class MysqlSettingRepository extends AbstractJdbcSettingRepository {
@Inject
public MysqlSettingRepository(@Named("settings") MysqlRepository<Setting> repository,
QueueService queueService,
ApplicationContext applicationContext) {
super(repository, applicationContext);
super(repository, queueService, applicationContext);
}
}

View File

@@ -2,6 +2,7 @@ package io.kestra.repository.mysql;
import io.kestra.core.models.templates.Template;
import io.kestra.core.models.templates.TemplateEnabled;
import io.kestra.core.queues.QueueService;
import io.kestra.jdbc.repository.AbstractJdbcTemplateRepository;
import io.micronaut.context.ApplicationContext;
import jakarta.inject.Inject;
@@ -17,8 +18,9 @@ import java.util.Arrays;
public class MysqlTemplateRepository extends AbstractJdbcTemplateRepository {
@Inject
public MysqlTemplateRepository(@Named("templates") MysqlRepository<Template> repository,
QueueService queueService,
ApplicationContext applicationContext) {
super(repository, applicationContext);
super(repository, queueService, applicationContext);
}
@Override

View File

@@ -1,8 +1,11 @@
package io.kestra.repository.mysql;
import io.kestra.core.models.triggers.Trigger;
import io.kestra.core.runners.ScheduleContextInterface;
import io.kestra.core.queues.QueueService;
import io.kestra.core.utils.DateUtils;
import io.kestra.jdbc.repository.AbstractJdbcTriggerRepository;
import io.kestra.jdbc.runner.JdbcSchedulerContext;
import io.kestra.jdbc.services.JdbcFilterService;
import jakarta.inject.Inject;
import jakarta.inject.Named;
@@ -11,6 +14,10 @@ import org.jooq.Condition;
import org.jooq.Field;
import org.jooq.impl.DSL;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.time.temporal.Temporal;
import java.util.Date;
import java.util.List;
@@ -19,17 +26,25 @@ import java.util.List;
public class MysqlTriggerRepository extends AbstractJdbcTriggerRepository {
@Inject
public MysqlTriggerRepository(@Named("triggers") MysqlRepository<Trigger> repository,
QueueService queueService,
JdbcFilterService filterService) {
super(repository, filterService);
super(repository, queueService, filterService);
}
@Override
protected Condition fullTextCondition(String query) {
return query == null ? DSL.trueCondition() : jdbcRepository.fullTextCondition(List.of("namespace", "flow_id", "trigger_id", "execution_id"), query);
return query == null ? DSL.noCondition() : jdbcRepository.fullTextCondition(List.of("namespace", "flow_id", "trigger_id", "execution_id"), query);
}
@Override
protected Field<Date> formatDateField(String dateField, DateUtils.GroupType groupType) {
return MysqlRepositoryUtils.formatDateField(dateField, groupType);
}
@Override
protected Temporal toNextExecutionTime(ZonedDateTime now) {
// next_execution_date in the table is stored in UTC
// convert 'now' to UTC LocalDateTime to avoid any timezone/offset interpretation by the database.
return now.withZoneSameInstant(ZoneOffset.UTC).toLocalDateTime();
}
}

View File

@@ -25,6 +25,7 @@ kestra:
server:
liveness:
enabled: false
termination-grace-period: 5s
service:
purge:
initial-delay: 1h

View File

@@ -2,6 +2,7 @@ package io.kestra.repository.postgres;
import io.kestra.core.events.CrudEvent;
import io.kestra.core.models.dashboards.Dashboard;
import io.kestra.core.queues.QueueService;
import io.kestra.core.repositories.QueryBuilderInterface;
import io.kestra.jdbc.repository.AbstractJdbcDashboardRepository;
import io.micronaut.context.event.ApplicationEventPublisher;
@@ -17,9 +18,10 @@ import java.util.List;
public class PostgresDashboardRepository extends AbstractJdbcDashboardRepository {
@Inject
public PostgresDashboardRepository(@Named("dashboards") PostgresRepository<Dashboard> repository,
QueueService queueService,
ApplicationEventPublisher<CrudEvent<Dashboard>> eventPublisher,
List<QueryBuilderInterface<?>> queryBuilders) {
super(repository, eventPublisher, queryBuilders);
super(repository, queueService, eventPublisher, queryBuilders);
}
@Override

View File

@@ -17,6 +17,6 @@ public abstract class PostgresDashboardRepositoryService {
conditions.add(jdbcRepository.fullTextCondition(Collections.singletonList("fulltext"), query));
}
return conditions.isEmpty() ? DSL.trueCondition() : DSL.and(conditions);
return conditions.isEmpty() ? DSL.noCondition() : DSL.and(conditions);
}
}

View File

@@ -3,6 +3,7 @@ package io.kestra.repository.postgres;
import io.kestra.core.models.QueryFilter;
import io.kestra.core.models.executions.Execution;
import io.kestra.core.models.flows.State;
import io.kestra.core.queues.QueueService;
import io.kestra.core.utils.DateUtils;
import io.kestra.core.utils.Either;
import io.kestra.jdbc.repository.AbstractJdbcExecutionRepository;
@@ -24,10 +25,11 @@ import java.util.*;
public class PostgresExecutionRepository extends AbstractJdbcExecutionRepository {
@Inject
public PostgresExecutionRepository(@Named("executions") PostgresRepository<Execution> repository,
QueueService queueService,
ApplicationContext applicationContext,
AbstractJdbcExecutorStateStorage executorStateStorage,
JdbcFilterService filterService) {
super(repository, applicationContext, executorStateStorage, filterService);
super(repository, queueService, applicationContext, executorStateStorage, filterService);
}
@Override

View File

@@ -26,7 +26,7 @@ public abstract class PostgresExecutionRepositoryService {
});
}
return conditions.isEmpty() ? DSL.trueCondition() : DSL.and(conditions);
return conditions.isEmpty() ? DSL.noCondition() : DSL.and(conditions);
}
public static Condition findLabelCondition(Either<Map<?, ?>, String> input, QueryFilter.Op operation) {
@@ -60,7 +60,7 @@ public abstract class PostgresExecutionRepositoryService {
if (!inConditions.isEmpty()) {
conditions.add(DSL.or(inConditions));
}
return conditions.isEmpty() ? DSL.trueCondition() : DSL.and(conditions);
return conditions.isEmpty() ? DSL.noCondition() : DSL.and(conditions);
}
public static Condition statesFilter(List<State.Type> state) {

View File

@@ -28,7 +28,7 @@ public abstract class PostgresFlowRepositoryService {
});
}
return conditions.isEmpty() ? DSL.trueCondition() : DSL.and(conditions);
return conditions.isEmpty() ? DSL.noCondition() : DSL.and(conditions);
}
public static Condition findSourceCodeCondition(AbstractJdbcRepository<? extends FlowInterface> jdbcRepository, String query) {
@@ -49,7 +49,7 @@ public abstract class PostgresFlowRepositoryService {
}
});
}
return conditions.isEmpty() ? DSL.trueCondition() : DSL.and(conditions);
return conditions.isEmpty() ? DSL.noCondition() : DSL.and(conditions);
}

View File

@@ -1,6 +1,7 @@
package io.kestra.repository.postgres;
import io.kestra.core.models.kv.PersistedKvMetadata;
import io.kestra.core.queues.QueueService;
import io.kestra.jdbc.repository.AbstractJdbcKvMetadataRepository;
import io.micronaut.context.ApplicationContext;
import jakarta.inject.Inject;
@@ -17,9 +18,10 @@ import java.util.List;
public class PostgresKvMetadataRepository extends AbstractJdbcKvMetadataRepository {
@Inject
public PostgresKvMetadataRepository(
@Named("kvMetadata") PostgresRepository<PersistedKvMetadata> repository
@Named("kvMetadata") PostgresRepository<PersistedKvMetadata> repository,
QueueService queueService
) {
super(repository);
super(repository, queueService);
}
@Override

View File

@@ -16,6 +16,6 @@ public abstract class PostgresKvMetadataRepositoryService {
conditions.add(jdbcRepository.fullTextCondition(List.of("fulltext"), query));
}
return conditions.isEmpty() ? DSL.trueCondition() : DSL.and(conditions);
return conditions.isEmpty() ? DSL.noCondition() : DSL.and(conditions);
}
}

View File

@@ -2,6 +2,7 @@ package io.kestra.repository.postgres;
import io.kestra.core.models.dashboards.filters.AbstractFilter;
import io.kestra.core.models.executions.LogEntry;
import io.kestra.core.queues.QueueService;
import io.kestra.core.utils.DateUtils;
import io.kestra.jdbc.repository.AbstractJdbcLogRepository;
import io.kestra.jdbc.services.JdbcFilterService;
@@ -26,8 +27,9 @@ public class PostgresLogRepository extends AbstractJdbcLogRepository {
@Inject
public PostgresLogRepository(@Named("logs") PostgresRepository<LogEntry> repository,
QueueService queueService,
JdbcFilterService filterService) {
super(repository, filterService);
super(repository, queueService, filterService);
}
@Override

View File

@@ -1,6 +1,7 @@
package io.kestra.repository.postgres;
import io.kestra.core.models.executions.MetricEntry;
import io.kestra.core.queues.QueueService;
import io.kestra.core.utils.DateUtils;
import io.kestra.jdbc.repository.AbstractJdbcMetricRepository;
import io.kestra.jdbc.services.JdbcFilterService;
@@ -17,8 +18,9 @@ import java.util.Date;
public class PostgresMetricRepository extends AbstractJdbcMetricRepository {
@Inject
public PostgresMetricRepository(@Named("metrics") PostgresRepository<MetricEntry> repository,
QueueService queueService,
JdbcFilterService filterService) {
super(repository, filterService);
super(repository, queueService, filterService);
}
@Override

View File

@@ -42,7 +42,7 @@ public class PostgresRepository<T> extends io.kestra.jdbc.AbstractJdbcRepository
@Override
public Condition fullTextCondition(List<String> fields, String query) {
if (query == null || query.equals("*")) {
return DSL.trueCondition();
return DSL.noCondition();
}
if (fields.size() > 1) {
@@ -106,7 +106,7 @@ public class PostgresRepository<T> extends io.kestra.jdbc.AbstractJdbcRepository
.sort(select, pageable)
.asTable("page")
)
.where(DSL.trueCondition()),
.where(DSL.noCondition()),
pageable
)
.fetch();

View File

@@ -1,6 +1,7 @@
package io.kestra.repository.postgres;
import io.kestra.core.models.Setting;
import io.kestra.core.queues.QueueService;
import io.kestra.jdbc.repository.AbstractJdbcSettingRepository;
import io.micronaut.context.ApplicationContext;
import jakarta.inject.Inject;
@@ -12,7 +13,8 @@ import jakarta.inject.Singleton;
public class PostgresSettingRepository extends AbstractJdbcSettingRepository {
@Inject
public PostgresSettingRepository(@Named("settings") PostgresRepository<Setting> repository,
QueueService queueService,
ApplicationContext applicationContext) {
super(repository, applicationContext);
super(repository, queueService, applicationContext);
}
}

View File

@@ -2,6 +2,7 @@ package io.kestra.repository.postgres;
import io.kestra.core.models.templates.Template;
import io.kestra.core.models.templates.TemplateEnabled;
import io.kestra.core.queues.QueueService;
import io.kestra.jdbc.repository.AbstractJdbcTemplateRepository;
import io.micronaut.context.ApplicationContext;
import jakarta.inject.Inject;
@@ -17,8 +18,9 @@ import java.util.Collections;
public class PostgresTemplateRepository extends AbstractJdbcTemplateRepository {
@Inject
public PostgresTemplateRepository(@Named("templates") PostgresRepository<Template> repository,
QueueService queueService,
ApplicationContext applicationContext) {
super(repository, applicationContext);
super(repository, queueService, applicationContext);
}
@Override

View File

@@ -1,6 +1,7 @@
package io.kestra.repository.postgres;
import io.kestra.core.models.triggers.Trigger;
import io.kestra.core.queues.QueueService;
import io.kestra.core.utils.DateUtils;
import io.kestra.jdbc.repository.AbstractJdbcTriggerRepository;
import io.kestra.jdbc.services.JdbcFilterService;
@@ -17,8 +18,9 @@ import java.util.Date;
public class PostgresTriggerRepository extends AbstractJdbcTriggerRepository {
@Inject
public PostgresTriggerRepository(@Named("triggers") PostgresRepository<Trigger> repository,
QueueService queueService,
JdbcFilterService filterService) {
super(repository, filterService);
super(repository, queueService, filterService);
}
@Override

View File

@@ -40,6 +40,7 @@ kestra:
server:
liveness:
enabled: false
termination-grace-period: 5s
service:
purge:
initial-delay: 1h

View File

@@ -74,7 +74,7 @@ public abstract class AbstractJdbcRepository<T> {
.of(io.kestra.jdbc.repository.AbstractJdbcRepository.field("value"), MAPPER.writeValueAsString(entity))
);
}
public int count(Condition condition) {
return getDslContextWrapper()
.transactionResult(configuration -> DSL
@@ -85,7 +85,7 @@ public abstract class AbstractJdbcRepository<T> {
.fetchOne(0, Integer.class)
);
}
public void persist(T entity) {
this.persist(entity, null);
}
@@ -223,8 +223,7 @@ public abstract class AbstractJdbcRepository<T> {
.from(this
.sort(select, Pageable.from(Sort.of(Order.asc(orderField))))
.asTable("page")
)
.where(DSL.trueCondition());
);
}
@SneakyThrows

View File

@@ -0,0 +1,439 @@
package io.kestra.jdbc.repository;
import io.kestra.core.queues.QueueService;
import io.kestra.core.repositories.ArrayListTotal;
import io.kestra.core.utils.ListUtils;
import io.micronaut.data.model.Pageable;
import org.jooq.*;
import org.jooq.Record;
import org.jooq.impl.DSL;
import reactor.core.publisher.Flux;
import reactor.core.publisher.FluxSink;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Stream;
/**
* Base JDBC repository for CRUD operations.
* <p>
* NOTE: it uses the <code>defaultFilter(tenantId)</code> for querying.
* If the child repository uses a default filter, it should override it.
* <p>
* For example, to avoid supporting the <code>deleted</code> column:
* <pre>{@code
* @Override
* protected Condition defaultFilter(String tenantId) {
* return buildTenantCondition(tenantId);
* }
*
* @Override
* protected Condition defaultFilter() {
* return DSL.noCondition();
* }
* }</pre>
*
* @param <T> the type of the persisted entity.
*/
public abstract class AbstractJdbcCrudRepository<T> extends AbstractJdbcRepository {
protected static final Field<String> KEY_FIELD = field("key", String.class);
protected static final Field<String> VALUE_FIELD = field("value", String.class);
protected io.kestra.jdbc.AbstractJdbcRepository<T> jdbcRepository;
protected QueueService queueService;
public AbstractJdbcCrudRepository(io.kestra.jdbc.AbstractJdbcRepository<T> jdbcRepository, QueueService queueService) {
this.jdbcRepository = jdbcRepository;
this.queueService = queueService;
}
/**
* Creates an item: persist it inside the database and return it.
* It uses an insert on conflict update to avoid concurrent write issues.
*/
public T create(T item) {
Map<Field<Object>, Object> fields = this.jdbcRepository.persistFields(item);
this.jdbcRepository.persist(item, fields);
return item;
}
/**
* Save an item: persist it inside the database and return it.
* It uses an insert on conflict update to avoid concurrent write issues.
*/
public T save(T item) {
Map<Field<Object>, Object> fields = this.jdbcRepository.persistFields(item);
this.jdbcRepository.persist(item, fields);
return item;
}
/**
* Creates an item: persist it inside the database and return it.
* It uses an insert on conflict update to avoid concurrent write issues.
*/
public T save(DSLContext context, T item) {
Map<Field<Object>, Object> fields = this.jdbcRepository.persistFields(item);
this.jdbcRepository.persist(item, context, fields);
return item;
}
/**
* Save a list of items: persist them inside the database and return the updated count.
*/
public int saveBatch(List<T> items) {
if (ListUtils.isEmpty(items)) {
return 0;
}
return this.jdbcRepository.persistBatch(items);
}
/**
* Update an item: persist it inside the database and return it.
* It uses an update statement, so the item must be already present in the database.
*/
public T update(T current) {
return this.jdbcRepository
.getDslContextWrapper()
.transactionResult(configuration -> {
DSL.using(configuration)
.update(this.jdbcRepository.getTable())
.set(this.jdbcRepository.persistFields((current)))
.where(KEY_FIELD.eq(queueService.key(current)))
.execute();
return current;
});
}
/**
* Find one item that matches the condition.
* <p>
* It uses LIMIT 1 and doesn't throw if the query returns more than one result.
*
* @see #findOne(String, Condition, boolean, OrderField...)
* @see #findOne(Condition, Condition, OrderField...)
*/
@SafeVarargs
protected final <F> Optional<T> findOne(String tenantId, Condition condition, OrderField<F>... orderByFields) {
return findOne(defaultFilter(tenantId), condition, orderByFields);
}
/**
* Find one item that matches the condition.
* You can use <code>allowDeleted</code> to decide whether deleted items should be included or not.
* <p>
* It uses LIMIT 1 and doesn't throw if the query returns more than one result.
*
* @see #findOne(String, Condition, OrderField...)
* @see #findOne(Condition, Condition, OrderField[])
*/
@SafeVarargs
protected final <F> Optional<T> findOne(String tenantId, Condition condition, boolean allowDeleted, OrderField<F>... orderByFields) {
return findOne(defaultFilter(tenantId, allowDeleted), condition, orderByFields);
}
/**
* Find one item that matches the condition.
* <p>
* It uses LIMIT 1 and doesn't throw if the query returns more than one result.
*
* @see #findOne(String, Condition, OrderField...)
* @see #findOne(String, Condition, boolean, OrderField...)
*/
@SafeVarargs
protected final <F> Optional<T> findOne(Condition defaultFilter, Condition condition, OrderField<F>... orderByFields) {
return this.jdbcRepository
.getDslContextWrapper()
.transactionResult(configuration -> {
var select = DSL
.using(configuration)
.select(VALUE_FIELD)
.from(this.jdbcRepository.getTable())
.where(defaultFilter)
.and(condition);
if (orderByFields != null) {
select.orderBy(orderByFields);
}
select.limit(1);
return this.jdbcRepository.fetchOne(select);
});
}
/**
* List all items that match the condition.
*
* @see #findAsync(String, Condition, OrderField...)
* @see #findPage(Pageable, String, Condition, OrderField...)
*/
@SafeVarargs
protected final <F> List<T> find(String tenantId, Condition condition, OrderField<F>... orderByFields) {
return find(defaultFilter(tenantId), condition, orderByFields);
}
/**
* List all items that match the condition.
* You can use <code>allowDeleted</code> to decide whether deleted items should be included or not.
*
* @see #findAsync(String, Condition, boolean, OrderField...)
* @see #findPage(Pageable, String, Condition, boolean, OrderField...)
*/
@SafeVarargs
protected final <F> List<T> find(String tenantId, Condition condition, boolean allowDeleted, OrderField<F>... orderByFields) {
return find(defaultFilter(tenantId, allowDeleted), condition, orderByFields);
}
/**
* List all items that match the condition.
*
* @see #findAsync(Condition, Condition, OrderField...)
* @see #findPage(Pageable, Condition, Condition, OrderField...)
*/
@SafeVarargs
protected final <F> List<T> find(Condition defaultFilter, Condition condition, OrderField<F>... orderByFields) {
return this.jdbcRepository
.getDslContextWrapper()
.transactionResult(configuration -> {
var select = DSL
.using(configuration)
.select(VALUE_FIELD)
.from(this.jdbcRepository.getTable())
.where(defaultFilter)
.and(condition);
if (orderByFields != null) {
select.orderBy(orderByFields);
}
return this.jdbcRepository.fetch(select);
});
}
/**
* Find all items that match the condition and return a reactive stream.
* To avoid any potential issues with databases that load all the resultset in memory, it batches the results by <code>FETCH_SIZE</code>.
*
* @see #find(String, Condition, OrderField...)
* @see #findPage(Pageable, String, Condition, OrderField...)
*/
@SafeVarargs
protected final <F> Flux<T> findAsync(String tenantId, Condition condition, OrderField<F>... orderByFields) {
return findAsync(defaultFilter(tenantId), condition, orderByFields);
}
/**
* Find all items that match the condition and return a reactive stream.
* To avoid any potential issues with databases that load all the resultset in memory, it batches the results by <code>FETCH_SIZE</code>.
* You can use <code>allowDeleted</code> to decide whether deleted items should be included or not.
*
* @see #find(String, Condition, boolean, OrderField...)
* @see #findPage(Pageable, String, Condition, boolean, OrderField...)
*/
@SafeVarargs
protected final <F> Flux<T> findAsync(String tenantId, Condition condition, boolean allowDeleted, OrderField<F>... orderByFields) {
return findAsync(defaultFilter(tenantId, allowDeleted), condition, orderByFields);
}
/**
* Find all items that match the condition and return a reactive stream.
* To avoid any potential issues with databases that load all the resultset in memory, it batches the results by <code>FETCH_SIZE</code>.
*
* @see #find(Condition, Condition, OrderField...)
* @see #findPage(Pageable, Condition, Condition, OrderField...)
*/
@SafeVarargs
protected final <F> Flux<T> findAsync(Condition defaultFilter, Condition condition, OrderField<F>... orderByFields) {
return Flux.create(emitter -> this.jdbcRepository
.getDslContextWrapper()
.transaction(configuration -> {
DSLContext context = DSL.using(configuration);
var select = context
.select(VALUE_FIELD)
.from(this.jdbcRepository.getTable())
.where(defaultFilter)
.and(condition);
if (orderByFields != null) {
select.orderBy(orderByFields);
}
try (Stream<Record1<String>> stream = select.fetchSize(FETCH_SIZE).stream()){
stream.map((Record record) -> jdbcRepository.map(record))
.forEach(emitter::next);
} finally {
emitter.complete();
}
}), FluxSink.OverflowStrategy.BUFFER);
}
/**
* Find a page of items that match the condition and return them.
*
* @see #find(String, Condition, OrderField...)
* @see #findAsync(String, Condition, OrderField...)
*/
@SafeVarargs
protected final <F> ArrayListTotal<T> findPage(Pageable pageable, String tenantId, Condition condition, OrderField<F>... orderByFields) {
return findPage(pageable, defaultFilter(tenantId), condition, orderByFields);
}
/**
* Find a page of items that match the condition and return them.
* You can use <code>allowDeleted</code> to decide whether deleted items should be included or not.
*
* @see #find(String, Condition, boolean, OrderField...)
* @see #findAsync(String, Condition, boolean, OrderField...)
*/
@SafeVarargs
protected final <F> ArrayListTotal<T> findPage(Pageable pageable, String tenantId, Condition condition, boolean allowDeleted, OrderField<F>... orderByFields) {
return findPage(pageable, defaultFilter(tenantId, allowDeleted), condition, orderByFields);
}
/**
* Find a page of items that match the condition and return them.
*
* @see #find(Condition, Condition, OrderField...)
* @see #findAsync(Condition, Condition, OrderField...)
*/
@SafeVarargs
protected final <F> ArrayListTotal<T> findPage(Pageable pageable, Condition defaultFilter, Condition condition, OrderField<F>... orderByFields) {
return this.jdbcRepository
.getDslContextWrapper()
.transactionResult(configuration -> {
DSLContext context = DSL.using(configuration);
var select = context
.select(VALUE_FIELD)
.from(this.jdbcRepository.getTable())
.where(defaultFilter)
.and(condition);
if (orderByFields != null) {
select.orderBy(orderByFields);
}
return this.jdbcRepository.fetchPage(context, select, pageable);
});
}
/**
* Find all items.
*
* @see #findAllAsync(String)
*/
public List<T> findAll(String tenantId) {
return findAll(defaultFilter(tenantId));
}
/**
* Find all items.
*
* @see #findAllAsync(Condition)
*/
protected List<T> findAll(Condition defaultFilter) {
return this.jdbcRepository
.getDslContextWrapper()
.transactionResult(configuration -> {
var select = DSL
.using(configuration)
.select(VALUE_FIELD)
.from(this.jdbcRepository.getTable())
.where(defaultFilter);
return this.jdbcRepository.fetch(select);
});
}
/**
* Find all items and return a reactive stream.
* To avoid any potential issues with databases that load all the resultset in memory, it batches the results by <code>FETCH_SIZE</code>.
*
* @see #findAll(String)
*/
public Flux<T> findAllAsync(String tenantId) {
return findAllAsync(defaultFilter(tenantId));
}
/**
* Find all items and return a reactive stream.
* To avoid any potential issues with databases that load all the resultset in memory, it batches the results by <code>FETCH_SIZE</code>.
*
* @see #findAll(Condition)
*/
protected Flux<T> findAllAsync(Condition defaultFilter) {
return Flux.create(emitter -> this.jdbcRepository
.getDslContextWrapper()
.transaction(configuration -> {
DSLContext context = DSL.using(configuration);
var select = context
.select(VALUE_FIELD)
.from(this.jdbcRepository.getTable())
.where(defaultFilter);
try (Stream<Record1<String>> stream = select.fetchSize(FETCH_SIZE).stream()){
stream.map((Record record) -> jdbcRepository.map(record))
.forEach(emitter::next);
} finally {
emitter.complete();
}
}), FluxSink.OverflowStrategy.BUFFER);
}
/**
* Find all items, for all tenants.
* WARNING: this method should never be used inside the API as it didn't enforce tenant selection!
*/
public List<T> findAllForAllTenants() {
return this.jdbcRepository
.getDslContextWrapper()
.transactionResult(configuration -> {
var select = DSL
.using(configuration)
.select(VALUE_FIELD)
.from(this.jdbcRepository.getTable())
.where(this.defaultFilter());
return this.jdbcRepository.fetch(select);
});
}
/**
* Count items that match the condition.
*
* @see #countAll(String)
* @see #countAllForAllTenants()
*/
protected long count(String tenantId, Condition condition) {
return this.jdbcRepository.count(this.defaultFilter(tenantId).and(condition));
}
/**
* Count all items.
*
* @see #count(String, Condition)
* @see #countAllForAllTenants()
*/
public long countAll(String tenantId) {
return this.jdbcRepository.count(this.defaultFilter(tenantId));
}
/**
* Count all items for all tenants.
* WARNING: this method should never be used inside the API as it didn't enforce tenant selection!
*
* @see #count(String, Condition)
* @see #countAll(String)
*/
public long countAllForAllTenants() {
return this.jdbcRepository.count(this.defaultFilter());
}
}

View File

@@ -7,6 +7,7 @@ import io.kestra.core.models.dashboards.DataFilter;
import io.kestra.core.models.dashboards.DataFilterKPI;
import io.kestra.core.models.dashboards.charts.DataChart;
import io.kestra.core.models.dashboards.charts.DataChartKPI;
import io.kestra.core.queues.QueueService;
import io.kestra.core.repositories.ArrayListTotal;
import io.kestra.core.repositories.DashboardRepositoryInterface;
import io.kestra.core.repositories.QueryBuilderInterface;
@@ -14,7 +15,6 @@ import io.kestra.plugin.core.dashboard.chart.kpis.KpiOption;
import io.micronaut.context.event.ApplicationEventPublisher;
import io.micronaut.data.model.Pageable;
import jakarta.validation.ConstraintViolationException;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.jooq.*;
import org.jooq.impl.DSL;
@@ -30,19 +30,17 @@ import java.util.Optional;
import static io.kestra.core.utils.MathUtils.roundDouble;
@Slf4j
@AllArgsConstructor
public abstract class AbstractJdbcDashboardRepository extends AbstractJdbcRepository implements DashboardRepositoryInterface {
protected io.kestra.jdbc.AbstractJdbcRepository<Dashboard> jdbcRepository;
public abstract class AbstractJdbcDashboardRepository extends AbstractJdbcCrudRepository<Dashboard> implements DashboardRepositoryInterface {
private final ApplicationEventPublisher<CrudEvent<Dashboard>> eventPublisher;
private final List<QueryBuilderInterface<?>> queryBuilders;
List<QueryBuilderInterface<?>> queryBuilders;
/**
* {@inheritDoc}
**/
@Override
public long count() {
return jdbcRepository.count(this.defaultFilter());
public AbstractJdbcDashboardRepository(io.kestra.jdbc.AbstractJdbcRepository<Dashboard> jdbcRepository,
QueueService queueService,
ApplicationEventPublisher<CrudEvent<Dashboard>> eventPublisher,
List<QueryBuilderInterface<?>> queryBuilders) {
super(jdbcRepository, queueService);
this.eventPublisher = eventPublisher;
this.queryBuilders = queryBuilders;
}
@@ -77,58 +75,12 @@ public abstract class AbstractJdbcDashboardRepository extends AbstractJdbcReposi
@Override
public ArrayListTotal<Dashboard> list(Pageable pageable, String tenantId, String query) {
return this.jdbcRepository
.getDslContextWrapper()
.transactionResult(configuration -> {
DSLContext context = DSL.using(configuration);
SelectConditionStep<Record1<Object>> select = context
.select(
field("value")
)
.from(jdbcRepository.getTable())
.where(this.defaultFilter(tenantId));
select = select.and(this.findCondition(query));
return this.jdbcRepository.fetchPage(context, select, pageable);
});
}
@Override
public List<Dashboard> findAll(String tenantId) {
return this.jdbcRepository
.getDslContextWrapper()
.transactionResult(configuration -> {
DSLContext context = DSL.using(configuration);
SelectConditionStep<Record1<Object>> select = context
.select(
field("value")
)
.from(jdbcRepository.getTable())
.where(this.defaultFilter(tenantId));
return this.jdbcRepository.fetch(select);
});
return findPage(pageable, tenantId, this.findCondition(query));
}
@Override
public List<Dashboard> findAllWithNoAcl(String tenantId) {
return this.jdbcRepository
.getDslContextWrapper()
.transactionResult(configuration -> {
DSLContext context = DSL.using(configuration);
SelectConditionStep<Record1<Object>> select = context
.select(
field("value")
)
.from(jdbcRepository.getTable())
.where(this.defaultFilterWithNoACL(tenantId));
return this.jdbcRepository.fetch(select);
});
return findAll(this.defaultFilterWithNoACL(tenantId));
}
@Override

View File

@@ -17,6 +17,7 @@ import io.kestra.core.models.flows.FlowScope;
import io.kestra.core.models.flows.State;
import io.kestra.core.queues.QueueFactoryInterface;
import io.kestra.core.queues.QueueInterface;
import io.kestra.core.queues.QueueService;
import io.kestra.core.repositories.ArrayListTotal;
import io.kestra.core.repositories.ExecutionRepositoryInterface;
import io.kestra.core.runners.Executor;
@@ -57,14 +58,13 @@ import java.util.stream.Stream;
import static io.kestra.core.models.QueryFilter.Field.KIND;
public abstract class AbstractJdbcExecutionRepository extends AbstractJdbcRepository implements ExecutionRepositoryInterface, JdbcQueueIndexerInterface<Execution> {
public abstract class AbstractJdbcExecutionRepository extends AbstractJdbcCrudRepository<Execution> implements ExecutionRepositoryInterface, JdbcQueueIndexerInterface<Execution> {
private static final int FETCH_SIZE = 100;
private static final Field<String> STATE_CURRENT_FIELD = field("state_current", String.class);
private static final Field<String> NAMESPACE_FIELD = field("namespace", String.class);
private static final Field<Object> START_DATE_FIELD = field("start_date");
private static final Condition NORMAL_KIND_CONDITION = field("kind").isNull();
protected final io.kestra.jdbc.AbstractJdbcRepository<Execution> jdbcRepository;
private final ApplicationEventPublisher<CrudEvent<Execution>> eventPublisher;
private final ApplicationContext applicationContext;
protected final AbstractJdbcExecutorStateStorage executorStateStorage;
@@ -100,11 +100,12 @@ public abstract class AbstractJdbcExecutionRepository extends AbstractJdbcReposi
@SuppressWarnings("unchecked")
public AbstractJdbcExecutionRepository(
io.kestra.jdbc.AbstractJdbcRepository<Execution> jdbcRepository,
QueueService queueService,
ApplicationContext applicationContext,
AbstractJdbcExecutorStateStorage executorStateStorage,
JdbcFilterService filterService
) {
this.jdbcRepository = jdbcRepository;
super(jdbcRepository, queueService);
this.executorStateStorage = executorStateStorage;
this.eventPublisher = applicationContext.getBean(ApplicationEventPublisher.class);
this.namespaceUtils = applicationContext.getBean(NamespaceUtils.class);
@@ -130,27 +131,8 @@ public abstract class AbstractJdbcExecutionRepository extends AbstractJdbcReposi
@Override
public Flux<Execution> findAllByTriggerExecutionId(String tenantId,
String triggerExecutionId) {
return Flux.create(
emitter -> this.jdbcRepository
.getDslContextWrapper()
.transaction(configuration -> {
SelectConditionStep<Record1<Object>> select = DSL
.using(configuration)
.select(field("value"))
.from(this.jdbcRepository.getTable())
.where(this.defaultFilter(tenantId))
.and(field("trigger_execution_id").eq(triggerExecutionId));
// fetchSize will fetch rows 100 by 100 even for databases where the driver loads all in memory
// using a stream will fetch lazily, otherwise all fetches would be done before starting emitting the items
try (var stream = select.fetchSize(FETCH_SIZE).stream()) {
stream.map(this.jdbcRepository::map).forEach(emitter::next);
} finally {
emitter.complete();
}
}),
FluxSink.OverflowStrategy.BUFFER
);
var condition = field("trigger_execution_id").eq(triggerExecutionId);
return findAsync(tenantId, condition);
}
/**
@@ -158,20 +140,10 @@ public abstract class AbstractJdbcExecutionRepository extends AbstractJdbcReposi
**/
@Override
public Optional<Execution> findLatestForStates(String tenantId, String namespace, String flowId, List<State.Type> states) {
return jdbcRepository
.getDslContextWrapper()
.transactionResult(configuration -> {
Select<Record1<Object>> from = DSL
.using(configuration)
.select(field("value"))
.from(this.jdbcRepository.getTable())
.where(this.defaultFilter(tenantId, false))
.and(field("namespace").eq(namespace))
.and(field("flow_id").eq(flowId))
.and(statesFilter(states))
.orderBy(field("start_date").desc());
return this.jdbcRepository.fetchOne(from);
});
var condition = field("namespace").eq(namespace)
.and(field("flow_id").eq(flowId))
.and(this.statesFilter(states));
return findOne(tenantId, condition, field("start_date").desc());
}
@Override
@@ -185,19 +157,12 @@ public abstract class AbstractJdbcExecutionRepository extends AbstractJdbcReposi
}
public Optional<Execution> findById(String tenantId, String id, boolean allowDeleted, boolean withAccessControl) {
return jdbcRepository
.getDslContextWrapper()
.transactionResult(configuration -> {
Select<Record1<Object>> from = DSL
.using(configuration)
.select(field("value"))
.from(this.jdbcRepository.getTable())
.where(withAccessControl ? this.defaultFilter(tenantId, allowDeleted) : this.defaultFilterWithNoACL(tenantId, allowDeleted))
.and(field("key").eq(id));
return this.jdbcRepository.fetchOne(from);
});
Condition defaultFilter = withAccessControl ? this.defaultFilter(tenantId, allowDeleted) : this.defaultFilterWithNoACL(tenantId, allowDeleted);
Condition condition = field("key").eq(id);
return findOne(defaultFilter, condition);
}
abstract protected Condition findCondition(String query, Map<String, String> labels);
protected Condition findQueryCondition(String query) {
@@ -218,20 +183,7 @@ public abstract class AbstractJdbcExecutionRepository extends AbstractJdbcReposi
@Nullable List<QueryFilter> filters
) {
return this.jdbcRepository
.getDslContextWrapper()
.transactionResult(configuration -> {
DSLContext context = DSL.using(configuration);
SelectConditionStep<Record1<Object>> select = this.findSelect(
context,
tenantId,
filters
);
return this.jdbcRepository.fetchPage(context, select, pageable);
});
return findPage(pageable, tenantId, this.computeFindCondition(filters));
}
@Override
@@ -283,27 +235,11 @@ public abstract class AbstractJdbcExecutionRepository extends AbstractJdbcReposi
);
}
private SelectConditionStep<Record1<Object>> findSelect(
DSLContext context,
@Nullable String tenantId,
@Nullable List<QueryFilter> filters
) {
SelectConditionStep<Record1<Object>> select = context
.select(
field("value")
)
.from(this.jdbcRepository.getTable())
.where(this.defaultFilter(tenantId, false));
private Condition computeFindCondition(@Nullable List<QueryFilter> filters) {
boolean hasKindFilter = filters != null && filters.stream()
.anyMatch(f -> KIND.value().equalsIgnoreCase(f.field().name()) );
if (!hasKindFilter) {
select = select.and(NORMAL_KIND_CONDITION);
}
select = select.and(this.filter(filters, "start_date", Resource.EXECUTION));
return select;
return hasKindFilter ? this.filter(filters, "start_date", Resource.EXECUTION) :
this.filter(filters, "start_date", Resource.EXECUTION).and(NORMAL_KIND_CONDITION);
}
private SelectConditionStep<Record1<Object>> findSelect(
@@ -345,43 +281,10 @@ public abstract class AbstractJdbcExecutionRepository extends AbstractJdbcReposi
return select;
}
@Override
public Flux<Execution> findAllAsync(@Nullable String tenantId) {
return Flux.create(emitter -> this.jdbcRepository
.getDslContextWrapper()
.transaction(configuration -> {
DSLContext context = DSL.using(configuration);
SelectConditionStep<Record1<Object>> select = context
.select(field("value"))
.from(this.jdbcRepository.getTable())
.where(this.defaultFilter(tenantId));
try (Stream<Record1<Object>> stream = select.fetchSize(FETCH_SIZE).stream()) {
stream.map((Record record) -> jdbcRepository.map(record))
.forEach(emitter::next);
} finally {
emitter.complete();
}
}), FluxSink.OverflowStrategy.BUFFER);
}
@Override
public ArrayListTotal<Execution> findByFlowId(String tenantId, String namespace, String id, Pageable pageable) {
return this.jdbcRepository
.getDslContextWrapper()
.transactionResult(configuration -> {
DSLContext context = DSL.using(configuration);
SelectConditionStep<Record1<Object>> select = context
.select(field("value"))
.from(this.jdbcRepository.getTable())
.where(this.defaultFilter(tenantId))
.and(field("namespace").eq(namespace))
.and(field("flow_id").eq(id));
return this.jdbcRepository.fetchPage(context, select, pageable);
});
var condition = field("namespace").eq(namespace).and(field("flow_id").eq(id));
return findPage(pageable, tenantId, condition);
}
@Override
@@ -867,18 +770,16 @@ public abstract class AbstractJdbcExecutionRepository extends AbstractJdbcReposi
.from(this.jdbcRepository.getTable())
.where(this.defaultFilter(tenantId))
.and(NORMAL_KIND_CONDITION)
.and(DSL.or(
ListUtils.emptyOnNull(flows).isEmpty() ?
DSL.trueCondition()
.and(ListUtils.isEmpty(flows) ?
DSL.noCondition()
:
DSL.or(
flows.stream()
.map(flow -> DSL.and(
field("namespace").eq(flow.getNamespace()),
field("flow_id").eq(flow.getId())
))
.toList()
)
DSL.or(
flows.stream()
.map(flow -> DSL.and(
field("namespace").eq(flow.getNamespace()),
field("flow_id").eq(flow.getId())
))
.toList()
)
);
@@ -892,47 +793,6 @@ public abstract class AbstractJdbcExecutionRepository extends AbstractJdbcReposi
});
}
@Override
public Execution save(Execution execution) {
Map<Field<Object>, Object> fields = this.jdbcRepository.persistFields(execution);
this.jdbcRepository.persist(execution, fields);
return execution;
}
@Override
public Execution save(DSLContext dslContext, Execution execution) {
Map<Field<Object>, Object> fields = this.jdbcRepository.persistFields(execution);
this.jdbcRepository.persist(execution, dslContext, fields);
return execution;
}
@Override
public int saveBatch(List<Execution> items) {
if (ListUtils.isEmpty(items)) {
return 0;
}
return this.jdbcRepository.persistBatch(items);
}
@Override
public Execution update(Execution execution) {
return this.jdbcRepository
.getDslContextWrapper()
.transactionResult(configuration -> {
DSL.using(configuration)
.update(this.jdbcRepository.getTable())
.set(this.jdbcRepository.persistFields((execution)))
.where(field("key").eq(execution.getId()))
.execute();
return execution;
});
}
@SneakyThrows
@Override
public Execution delete(Execution execution) {

View File

@@ -1,7 +1,6 @@
package io.kestra.jdbc.repository;
import io.kestra.core.models.flows.FlowInterface;
import io.kestra.core.models.flows.FlowWithSource;
import io.kestra.core.models.topologies.FlowTopology;
import io.kestra.core.repositories.FlowTopologyRepositoryInterface;
import io.kestra.jdbc.runner.JdbcQueueIndexerInterface;
@@ -169,6 +168,7 @@ public abstract class AbstractJdbcFlowTopologyRepository extends AbstractJdbcRep
.set(this.jdbcRepository.persistFields(flowTopology));
}
@Override
public FlowTopology save(FlowTopology flowTopology) {
this.jdbcRepository.persist(flowTopology);
@@ -184,6 +184,7 @@ public abstract class AbstractJdbcFlowTopologyRepository extends AbstractJdbcRep
return flowTopology;
}
protected Condition buildTenantCondition(String prefix, String tenantId) {
return tenantId == null ? field(prefix + "_tenant_id").isNull() : field(prefix + "_tenant_id").eq(tenantId);
}

Some files were not shown because too many files have changed in this diff Show More