diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index 659e4a8cd..8a71d8dc2 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -7,8 +7,8 @@ assignees: '' --- -Please read our [contributor guide](https://github.com/Netflix/conductor/blob/main/CONTRIBUTING.md) before creating an issue. -Also consider discussing your idea on the [discussion forum](https://github.com/Netflix/conductor/discussions) first. +Please read our [contributor guide](https://github.com/conductor-oss/conductor/blob/main/CONTRIBUTING.md) before creating an issue. +Also consider discussing your idea on the [discussion forum](https://github.com/conductor-oss/conductor/discussions) first. ## Describe the Feature Request _A clear and concise description of what the feature request is._ diff --git a/.github/dependabot.yml b/.github/dependabot.yml index ef87e0b82..fa854fcdc 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -5,9 +5,9 @@ updates: schedule: interval: "weekly" reviewers: - - "aravindanr" - - "jxu-nflx" - - "apanicker-nflx" + - "v1r3n" + - "boney9" + - "c4lm" - package-ecosystem: "github-actions" directory: "/" schedule: diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 4cd3eb440..8367fbc9a 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -3,7 +3,7 @@ Pull Request type - [ ] Bugfix - [ ] Feature - [ ] Refactoring (no functional changes, no api changes) -- [ ] Build related changes (Please run `./gradlew generateLock saveLock` to refresh dependencies) +- [ ] Build related changes - [ ] WHOSUSING.md - [ ] Other (please describe): diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9528884b4..a25c97dd2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -42,12 +42,7 @@ jobs: if: github.event_name != 'pull_request' && github.ref == 'refs/heads/main' run: | echo "Running build for commit ${{ github.sha }}" - ./gradlew build snapshot --scan - env: - NETFLIX_OSS_SIGNING_KEY: ${{ secrets.ORG_SIGNING_KEY }} - NETFLIX_OSS_SIGNING_PASSWORD: ${{ secrets.ORG_SIGNING_PASSWORD }} - NETFLIX_OSS_REPO_USERNAME: ${{ secrets.ORG_NETFLIXOSS_USERNAME }} - NETFLIX_OSS_REPO_PASSWORD: ${{ secrets.ORG_NETFLIXOSS_PASSWORD }} + ./gradlew build - name: Publish Test Report uses: mikepenz/action-junit-report@v3 if: always() diff --git a/.github/workflows/generate_gh_pages.yml b/.github/workflows/generate_gh_pages.yml new file mode 100644 index 000000000..8c429e1b8 --- /dev/null +++ b/.github/workflows/generate_gh_pages.yml @@ -0,0 +1,18 @@ +name: Publish docs via GitHub Pages +on: + workflow_dispatch + +jobs: + build: + name: Deploy docs + runs-on: ubuntu-latest + steps: + - name: Checkout main + uses: actions/checkout@v2 + + - name: Deploy docs + uses: mhausenblas/mkdocs-deploy-gh-pages@master + env: + GITHUB_TOKEN: ${{ secrets.DOCSITE_TOKEN }} + CONFIG_FILE: mkdocs.yml + REQUIREMENTS: requirements.txt diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 3bf0960ae..51b514ffa 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -1,4 +1,4 @@ -name: Publish to NetflixOSS and Maven Central +name: Publish Conductor OSS toMaven Central on: release: types: @@ -28,39 +28,13 @@ jobs: key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }} restore-keys: | ${{ runner.os }}-gradle- - - name: Publish candidate - if: startsWith(github.ref, 'refs/tags/v') && contains(github.ref, '-rc.') - run: ./gradlew -Prelease.useLastTag=true candidate --scan - env: - NETFLIX_OSS_SONATYPE_USERNAME: ${{ secrets.ORG_SONATYPE_USERNAME }} - NETFLIX_OSS_SONATYPE_PASSWORD: ${{ secrets.ORG_SONATYPE_PASSWORD }} - NETFLIX_OSS_SIGNING_KEY: ${{ secrets.ORG_SIGNING_KEY }} - NETFLIX_OSS_SIGNING_PASSWORD: ${{ secrets.ORG_SIGNING_PASSWORD }} - NETFLIX_OSS_REPO_USERNAME: ${{ secrets.ORG_NETFLIXOSS_USERNAME }} - NETFLIX_OSS_REPO_PASSWORD: ${{ secrets.ORG_NETFLIXOSS_PASSWORD }} - name: Publish release - if: startsWith(github.ref, 'refs/tags/v') && (!contains(github.ref, '-rc.')) - run: ./gradlew -Prelease.useLastTag=true final --scan - env: - NETFLIX_OSS_SONATYPE_USERNAME: ${{ secrets.ORG_SONATYPE_USERNAME }} - NETFLIX_OSS_SONATYPE_PASSWORD: ${{ secrets.ORG_SONATYPE_PASSWORD }} - NETFLIX_OSS_SIGNING_KEY: ${{ secrets.ORG_SIGNING_KEY }} - NETFLIX_OSS_SIGNING_PASSWORD: ${{ secrets.ORG_SIGNING_PASSWORD }} - NETFLIX_OSS_REPO_USERNAME: ${{ secrets.ORG_NETFLIXOSS_USERNAME }} - NETFLIX_OSS_REPO_PASSWORD: ${{ secrets.ORG_NETFLIXOSS_PASSWORD }} - - name: Publish tag to community repo - if: startsWith(github.ref, 'refs/tags/v') run: | - export TAG=$(git describe --tags --abbrev=0) - echo "Current release version is $TAG" - echo "Triggering community build" - curl \ - -H "Accept: application/vnd.github.v3+json" \ - -H "Authorization: Bearer ${{ secrets.COMMUNITY_REPO_TRIGGER }}" \ - -X POST https://api.github.com/repos/Netflix/conductor-community/dispatches \ - -d '{"event_type": "publish_build","client_payload": {"tag":"'"$TAG"'"}}' - - name: Publish Test Report - uses: mikepenz/action-junit-report@v3 - if: always() # always run even if the previous step fails - with: - report_paths: '**/build/test-results/test/TEST-*.xml' + export VERSION="${{github.ref_name}}" + export PUBLISH_VERSION=`echo ${VERSION:1}` + echo Publishing version $PUBLISH_VERSION + ./gradlew publish -Pversion=$PUBLISH_VERSION -Pusername=${{ secrets.SONATYPE_USERNAME }} -Ppassword=${{ secrets.SONATYPE_PASSWORD }} + env: + ORG_GRADLE_PROJECT_signingKeyId: ${{ secrets.SIGNING_KEY_ID }} + ORG_GRADLE_PROJECT_signingKey: ${{ secrets.SIGNING_KEY }} + ORG_GRADLE_PROJECT_signingPassword: ${{ secrets.SIGNING_PASSWORD }} \ No newline at end of file diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml deleted file mode 100644 index a90156f3b..000000000 --- a/.github/workflows/stale.yml +++ /dev/null @@ -1,28 +0,0 @@ -name: Close stale issues and pull requests - -on: - schedule: - - cron: "0 0 * * *" - -permissions: - contents: read - -jobs: - stale: - permissions: - issues: write # for actions/stale to close stale issues - pull-requests: write # for actions/stale to close stale PRs - runs-on: ubuntu-latest - steps: - - uses: actions/stale@v6 - with: - repo-token: ${{ secrets.GITHUB_TOKEN }} - stale-issue-message: 'This issue is stale, because it has been open for 45 days with no activity. Remove the stale label or comment, or this will be closed in 7 days.' - close-issue-message: 'This issue was closed, because it has been stalled for 7 days with no activity.' - stale-pr-message: 'This PR is stale, because it has been open for 45 days with no activity. Remove the stale label or comment, or this will be closed in 7 days.' - close-pr-message: 'This PR was closed, because it has been stalled for 7 days with no activity.' - days-before-issue-stale: 45 - days-before-issue-close: 7 - days-before-pr-stale: 45 - days-before-pr-close: 7 - exempt-issue-labels: 'type: bug,enhancement,work_in_progress,help_wanted' diff --git a/.github/workflows/update-gradle-wrapper.yml b/.github/workflows/update-gradle-wrapper.yml deleted file mode 100644 index 831e6d5aa..000000000 --- a/.github/workflows/update-gradle-wrapper.yml +++ /dev/null @@ -1,19 +0,0 @@ -name: Update Gradle Wrapper - -on: - schedule: - - cron: "0 0 * * *" - workflow_dispatch: - -jobs: - update-gradle-wrapper: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - name: Set up Zulu JDK 17 - uses: actions/setup-java@v3 - with: - distribution: 'zulu' - java-version: '17' - - name: Update Gradle Wrapper - uses: gradle-update/update-gradle-wrapper-action@v1 diff --git a/CHANGELOG.md b/CHANGELOG.md index c17a8bda8..e69de29bb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,371 +0,0 @@ -Conductor has been upgraded to use the SpringBoot framework and requires Java11 or above. -#### NOTE: The java clients (conductor-client, conductor-client-spring, conductor-grpc-client) are still compiled using Java8 to ensure backward compatibility and smoother migration. - -## Removals/Deprecations -- Removed support for EmbeddedElasticSearch -- Removed deprecated constructors in DynoQueueDAO -- Removed deprecated methods in the Worker interface -- Removed OAuth Support in HTTP task (Looking for contributions for OAuth/OAuth2.0) -- Removed deprecated fields and methods in the Workflow object -- Removed deprecated fields and methods in the Task object -- Removed deprecated fields and methods in the WorkflowTask object - -Removed unused methods from QueueDAO: -- List pop(String, int, int, long) -- List pollMessages(String, int, int, long) - -Removed APIs: -- GET /tasks/in_progress/{tasktype} -- GET /tasks/in_progress/{workflowId}/{taskRefName} -- POST /tasks/{taskId}/ack -- POST /tasks/queue/requeue -- DELETE /queue/{taskType}/{taskId} - - -- GET /event/queues -- GET /event/queues/providers - - -- void restart(String) in workflow client -- List getPendingTasksByType(String, String, Integer) in task client -- Task getPendingTaskForWorkflow(String, String) in task client -- boolean preAck(Task) in Worker -- int getPollCount() in Worker - -## What's changed -Changes to configurations: - -### `azureblob-storage` module: - -| Old | New | Default | -| --- | --- | --- | -| workflow.external.payload.storage.azure_blob.connection_string | conductor.external-payload-storage.azureblob.connectionString | null | -| workflow.external.payload.storage.azure_blob.container_name | conductor.external-payload-storage.azureblob.containerName | conductor-payloads | -| workflow.external.payload.storage.azure_blob.endpoint | conductor.external-payload-storage.azureblob.endpoint | null | -| workflow.external.payload.storage.azure_blob.sas_token | conductor.external-payload-storage.azureblob.sasToken | null | -| workflow.external.payload.storage.azure_blob.signedurlexpirationseconds | conductor.external-payload-storage.azureblob.signedUrlExpirationDuration | 5s | -| workflow.external.payload.storage.azure_blob.workflow_input_path | conductor.external-payload-storage.azureblob.workflowInputPath | workflow/input/ | -| workflow.external.payload.storage.azure_blob.workflow_output_path | conductor.external-payload-storage.azureblob.workflowOutputPath | workflow/output/ | -| workflow.external.payload.storage.azure_blob.task_input_path | conductor.external-payload-storage.azureblob.taskInputPath | task/input/ | -| workflow.external.payload.storage.azure_blob.task_output_path | conductor.external-payload-storage.azureblob.taskOutputPath | task/output/ | - -### `cassandra-persistence` module: - -| Old | New | Default | -| --- | --- | --- | -| workflow.cassandra.host | conductor.cassandra.hostAddress | 127.0.0.1 | -| workflow.cassandra.port | conductor.cassandra.port | 9142 | -| workflow.cassandra.cluster | conductor.cassandra.cluster | "" | -| workflow.cassandra.keyspace | conductor.cassandra.keyspace | conductor | -| workflow.cassandra.shard.size | conductor.cassandra.shardSize | 100 | -| workflow.cassandra.replication.strategy | conductor.cassandra.replicationStrategy | SimpleStrategy | -| workflow.cassandra.replication.factor.key | conductor.cassandra.replicationFactorKey | replication_factor | -| workflow.cassandra.replication.factor.value | conductor.cassandra.replicationFactorValue | 3 | -| workflow.cassandra.read.consistency.level | conductor.cassandra.readConsistencyLevel | LOCAL_QUORUM | -| workflow.cassandra.write.consistency.level | conductor.cassandra.writeConsistencyLevel | LOCAL_QUORUM | -| conductor.taskdef.cache.refresh.time.seconds | conductor.cassandra.taskDefCacheRefreshInterval | 60s | -| conductor.eventhandler.cache.refresh.time.seconds | conductor.cassandra.eventHandlerCacheRefreshInterval | 60s | -| workflow.event.execution.persistence.ttl.seconds | conductor.cassandra.eventExecutionPersistenceTTL | 0s | - -### `contribs` module: - -| Old | New | Default | -| --- | --- | --- | -| workflow.archival.ttl.seconds | conductor.workflow-status-listener.archival.ttlDuration | 0s | -| workflow.archival.delay.queue.worker.thread.count | conductor.workflow-status-listener.archival.delayQueueWorkerThreadCount | 5 | -| workflow.archival.delay.seconds | conductor.workflow-status-listener.archival.delaySeconds | 60 | -| | | -| workflowstatuslistener.publisher.success.queue | conductor.workflow-status-listener.queue-publisher.successQueue | _callbackSuccessQueue | -| workflowstatuslistener.publisher.failure.queue | conductor.workflow-status-listener.queue-publisher.failureQueue | _callbackFailureQueue | -| | | | -| com.netflix.conductor.contribs.metrics.LoggingMetricsModule.reportPeriodSeconds | conductor.metrics-logger.reportInterval | 30s | -| | | | -| workflow.event.queues.amqp.batchSize | conductor.event-queues.amqp.batchSize | 1 | -| workflow.event.queues.amqp.pollTimeInMs | conductor.event-queues.amqp.pollTimeDuration | 100ms | -| workflow.event.queues.amqp.hosts | conductor.event-queues.amqp.hosts | localhost | -| workflow.event.queues.amqp.username | conductor.event-queues.amqp.username | guest | -| workflow.event.queues.amqp.password | conductor.event-queues.amqp.password | guest | -| workflow.event.queues.amqp.virtualHost | conductor.event-queues.amqp.virtualHost | / | -| workflow.event.queues.amqp.port | conductor.event-queues.amqp.port.port | 5672 | -| workflow.event.queues.amqp.connectionTimeout | conductor.event-queues.amqp.connectionTimeout | 60000ms | -| workflow.event.queues.amqp.useNio | conductor.event-queues.amqp.useNio | false | -| workflow.event.queues.amqp.durable | conductor.event-queues.amqp.durable | true | -| workflow.event.queues.amqp.exclusive | conductor.event-queues.amqp.exclusive | false | -| workflow.event.queues.amqp.autoDelete | conductor.event-queues.amqp.autoDelete | false | -| workflow.event.queues.amqp.contentType | conductor.event-queues.amqp.contentType | application/json | -| workflow.event.queues.amqp.contentEncoding | conductor.event-queues.amqp.contentEncoding | UTF-8 | -| workflow.event.queues.amqp.amqp_exchange | conductor.event-queues.amqp.exchangeType | topic | -| workflow.event.queues.amqp.deliveryMode | conductor.event-queues.amqp.deliveryMode | 2 | -| workflow.listener.queue.useExchange | conductor.event-queues.amqp.useExchange | true | -| workflow.listener.queue.prefix | conductor.event-queues.amqp.listenerQueuePrefix | "" | -| | | | -| io.nats.streaming.clusterId | conductor.event-queues.nats-stream.clusterId | test-cluster | -| io.nats.streaming.durableName | conductor.event-queues.nats-stream.durableName | null | -| io.nats.streaming.url | conductor.event-queues.nats-stream.url | nats://localhost:4222 | -| | | | -| workflow.event.queues.sqs.batchSize | conductor.event-queues.sqs.batchSize | 1 | -| workflow.event.queues.sqs.pollTimeInMS | conductor.event-queues.sqs.pollTimeDuration | 100ms | -| workflow.event.queues.sqs.visibilityTimeoutInSeconds | conductor.event-queues.sqs.visibilityTimeout | 60s | -| workflow.listener.queue.prefix | conductor.event-queues.sqs.listenerQueuePrefix | "" | -| workflow.listener.queue.authorizedAccounts | conductor.event-queues.sqs.authorizedAccounts | "" | -| | | | -| workflow.external.payload.storage.s3.bucket | conductor.external-payload-storage.s3.bucketName | conductor_payloads | -| workflow.external.payload.storage.s3.signedurlexpirationseconds | conductor.external-payload-storage.s3.signedUrlExpirationDuration | 5s | -| workflow.external.payload.storage.s3.region | conductor.external-payload-storage.s3.region | us-east-1 | -| | | | -| http.task.read.timeout | conductor.tasks.http.readTimeout | 150ms | -| http.task.connect.timeout | conductor.tasks.http.connectTimeout | 100ms | -| | | | -| kafka.publish.request.timeout.ms | conductor.tasks.kafka-publish.requestTimeout | 100ms | -| kafka.publish.max.block.ms | conductor.tasks.kafka-publish.maxBlock | 500ms | -| kafka.publish.producer.cache.size | conductor.tasks.kafka-publish.cacheSize | 10 | -| kafka.publish.producer.cache.time.ms | conductor.tasks.kafka-publish.cacheTime | 120000ms | - -### `core` module: - -| Old | New | Default | -| --- | --- | --- | -| environment | _removed_ | | -| STACK | conductor.app.stack | test | -| APP_ID | conductor.app.appId | conductor | -| workflow.executor.service.max.threads | conductor.app.executorServiceMaxThreadCount | 50 | -| decider.sweep.frequency.seconds | conductor.app.sweepFrequency | 30s | -| workflow.sweeper.thread.count | conductor.app.sweeperThreadCount | 5 | -| - | conductor.app.sweeperWorkflowPollTimeout | 2000ms | -| workflow.event.processor.thread.count | conductor.app.eventProcessorThreadCount | 2 | -| workflow.event.message.indexing.enabled | conductor.app.eventMessageIndexingEnabled | true | -| workflow.event.execution.indexing.enabled | conductor.app.eventExecutionIndexingEnabled | true | -| workflow.decider.locking.enabled | conductor.app.workflowExecutionLockEnabled | false | -| workflow.locking.lease.time.ms | conductor.app.lockLeaseTime | 60000ms | -| workflow.locking.time.to.try.ms | conductor.app.lockTimeToTry | 500ms | -| tasks.active.worker.lastpoll | conductor.app.activeWorkerLastPollTimeout | 10s | -| task.queue.message.postponeSeconds | conductor.app.taskExecutionPostponeDuration | 60s | -| workflow.taskExecLog.indexing.enabled | conductor.app.taskExecLogIndexingEnabled | true | -| async.indexing.enabled | conductor.app.asyncIndexingEnabled | false | -| workflow.system.task.worker.thread.count | conductor.app.systemTaskWorkerThreadCount | # available processors * 2 | -| workflow.system.task.worker.callback.seconds | conductor.app.systemTaskWorkerCallbackDuration | 30s | -| workflow.system.task.worker.poll.interval | conductor.app.systemTaskWorkerPollInterval | 50s | -| workflow.system.task.worker.executionNameSpace | conductor.app.systemTaskWorkerExecutionNamespace | "" | -| workflow.isolated.system.task.worker.thread.count | conductor.app.isolatedSystemTaskWorkerThreadCount | 1 | -| workflow.system.task.queue.pollCount | conductor.app.systemTaskMaxPollCount | 1 | -| async.update.short.workflow.duration.seconds | conductor.app.asyncUpdateShortRunningWorkflowDuration | 30s | -| async.update.delay.seconds | conductor.app.asyncUpdateDelay | 60s | -| summary.input.output.json.serialization.enabled | conductor.app.summary-input-output-json-serialization.enabled | false | -| workflow.owner.email.mandatory | conductor.app.ownerEmailMandatory | true | -| workflow.repairservice.enabled | conductor.app.workflowRepairServiceEnabled | false | -| workflow.event.queue.scheduler.poll.thread.count | conductor.app.eventSchedulerPollThreadCount | # CPU cores | -| workflow.dyno.queues.pollingInterval | conductor.app.eventQueuePollInterval | 100ms | -| workflow.dyno.queues.pollCount | conductor.app.eventQueuePollCount | 10 | -| workflow.dyno.queues.longPollTimeout | conductor.app.eventQueueLongPollTimeout | 1000ms | -| conductor.workflow.input.payload.threshold.kb | conductor.app.workflowInputPayloadSizeThreshold | 5120KB | -| conductor.max.workflow.input.payload.threshold.kb | conductor.app.maxWorkflowInputPayloadSizeThreshold | 10240KB | -| conductor.workflow.output.payload.threshold.kb | conductor.app.workflowOutputPayloadSizeThreshold | 5120KB | -| conductor.max.workflow.output.payload.threshold.kb | conductor.app.maxWorkflowOutputPayloadSizeThreshold | 10240KB | -| conductor.task.input.payload.threshold.kb | conductor.app.taskInputPayloadSizeThreshold | 3072KB | -| conductor.max.task.input.payload.threshold.kb | conductor.app.maxTaskInputPayloadSizeThreshold | 10240KB | -| conductor.task.output.payload.threshold.kb | conductor.app.taskOutputPayloadSizeThreshold | 3072KB | -| conductor.max.task.output.payload.threshold.kb | conductor.app.maxTaskOutputPayloadSizeThreshold | 10240KB | -| conductor.max.workflow.variables.payload.threshold.kb | conductor.app.maxWorkflowVariablesPayloadSizeThreshold | 256KB | -| | | | -| workflow.isolated.system.task.enable | conductor.app.isolatedSystemTaskEnabled | false | -| workflow.isolated.system.task.poll.time.secs | conductor.app.isolatedSystemTaskQueuePollInterval | 10s | -| | | | -| workflow.task.pending.time.threshold.minutes | conductor.app.taskPendingTimeThreshold | 60m | -| | | | -| workflow.monitor.metadata.refresh.counter | conductor.workflow-monitor.metadataRefreshInterval | 10 | -| workflow.monitor.stats.freq.seconds | conductor.workflow-monitor.statsFrequency | 60s | - -### `es6-persistence` module: - -| Old | New | Default | -| --- | --- | --- | -| workflow.elasticsearch.version | conductor.elasticsearch.version | 6 | -| workflow.elasticsearch.url | conductor.elasticsearch.url | localhost:9300 | -| workflow.elasticsearch.index.name | conductor.elasticsearch.indexPrefix | conductor | -| workflow.elasticsearch.tasklog.index.name | _removed_ | | -| workflow.elasticsearch.cluster.health.color | conductor.elasticsearch.clusterHealthColor | green | -| workflow.elasticsearch.archive.search.batchSize | _removed_ | | -| workflow.elasticsearch.index.batchSize | conductor.elasticsearch.indexBatchSize | 1 | -| workflow.elasticsearch.async.dao.worker.queue.size | conductor.elasticsearch.asyncWorkerQueueSize | 100 | -| workflow.elasticsearch.async.dao.max.pool.size | conductor.elasticsearch.asyncMaxPoolSize | 12 | -| workflow.elasticsearch.async.buffer.flush.timeout.seconds | conductor.elasticsearch.asyncBufferFlushTimeout | 10s | -| workflow.elasticsearch.index.shard.count | conductor.elasticsearch.indexShardCount | 5 | -| workflow.elasticsearch.index.replicas.count | conductor.elasticsearch.indexReplicasCount | 1 | -| tasklog.elasticsearch.query.size | conductor.elasticsearch.taskLogResultLimit | 10 | -| workflow.elasticsearch.rest.client.connectionRequestTimeout.milliseconds | conductor.elasticsearch.restClientConnectionRequestTimeout | -1 | -| workflow.elasticsearch.auto.index.management.enabled | conductor.elasticsearch.autoIndexManagementEnabled | true | -| workflow.elasticsearch.document.type.override | conductor.elasticsearch.documentTypeOverride | "" | - -### `es7-persistence` module: - -| Old | New | Default | -| --- | --- | --- | -| workflow.elasticsearch.version | conductor.elasticsearch.version | 7 | -| workflow.elasticsearch.url | conductor.elasticsearch.url | localhost:9300 | -| workflow.elasticsearch.index.name | conductor.elasticsearch.indexPrefix | conductor | -| workflow.elasticsearch.tasklog.index.name | _removed_ | | -| workflow.elasticsearch.cluster.health.color | conductor.elasticsearch.clusterHealthColor | green | -| workflow.elasticsearch.archive.search.batchSize | _removed_ | | -| workflow.elasticsearch.index.batchSize | conductor.elasticsearch.indexBatchSize | 1 | -| workflow.elasticsearch.async.dao.worker.queue.size | conductor.elasticsearch.asyncWorkerQueueSize | 100 | -| workflow.elasticsearch.async.dao.max.pool.size | conductor.elasticsearch.asyncMaxPoolSize | 12 | -| workflow.elasticsearch.async.buffer.flush.timeout.seconds | conductor.elasticsearch.asyncBufferFlushTimeout | 10s | -| workflow.elasticsearch.index.shard.count | conductor.elasticsearch.indexShardCount | 5 | -| workflow.elasticsearch.index.replicas.count | conductor.elasticsearch.indexReplicasCount | 1 | -| tasklog.elasticsearch.query.size | conductor.elasticsearch.taskLogResultLimit | 10 | -| workflow.elasticsearch.rest.client.connectionRequestTimeout.milliseconds | conductor.elasticsearch.restClientConnectionRequestTimeout | -1 | -| workflow.elasticsearch.auto.index.management.enabled | conductor.elasticsearch.autoIndexManagementEnabled | true | -| workflow.elasticsearch.document.type.override | conductor.elasticsearch.documentTypeOverride | "" | -| workflow.elasticsearch.basic.auth.username | conductor.elasticsearch.username | "" | -| workflow.elasticsearch.basic.auth.password | conductor.elasticsearch.password | "" | - -### `grpc-server` module: - -| Old | New | Default | -| --- | --- | --- | -| conductor.grpc.server.port | conductor.grpc-server.port | 8090 | -| conductor.grpc.server.reflectionEnabled | conductor.grpc-server.reflectionEnabled | true | - -### `mysql-persistence` module (v3.0.0 - v3.0.5): - -| Old | New | Default | -| --- | --- | --- | -| jdbc.url | conductor.mysql.jdbcUrl | jdbc:mysql://localhost:3306/conductor | -| jdbc.username | conductor.mysql.jdbcUsername | conductor | -| jdbc.password | conductor.mysql.jdbcPassword | password | -| flyway.enabled | conductor.mysql.flywayEnabled | true | -| flyway.table | conductor.mysql.flywayTable | null | -| conductor.mysql.connection.pool.size.max | conductor.mysql.connectionPoolMaxSize | -1 | -| conductor.mysql.connection.pool.idle.min | conductor.mysql.connectionPoolMinIdle | -1 | -| conductor.mysql.connection.lifetime.max | conductor.mysql.connectionMaxLifetime | 30m | -| conductor.mysql.connection.idle.timeout | conductor.mysql.connectionIdleTimeout | 10m | -| conductor.mysql.connection.timeout | conductor.mysql.connectionTimeout | 30s | -| conductor.mysql.transaction.isolation.level | conductor.mysql.transactionIsolationLevel | "" | -| conductor.mysql.autocommit | conductor.mysql.autoCommit | false | -| conductor.taskdef.cache.refresh.time.seconds | conductor.mysql.taskDefCacheRefreshInterval | 60s | - -### `mysql-persistence` module (v3.0.5+): - -| Old | New | -| --- | --- | -| jdbc.url | spring.datasource.url | -| jdbc.username | spring.datasource.username | -| jdbc.password | spring.datasource.password | -| flyway.enabled | spring.flyway.enabled | -| flyway.table | spring.flyway.table | -| conductor.mysql.connection.pool.size.max | spring.datasource.hikari.maximum-pool-size | -| conductor.mysql.connection.pool.idle.min | spring.datasource.hikari.minimum-idle | -| conductor.mysql.connection.lifetime.max | spring.datasource.hikari.max-lifetime | -| conductor.mysql.connection.idle.timeout | spring.datasource.hikari.idle-timeout | -| conductor.mysql.connection.timeout | spring.datasource.hikari.connection-timeout | -| conductor.mysql.transaction.isolation.level | spring.datasource.hikari.transaction-isolation | -| conductor.mysql.autocommit | spring.datasource.hikari.auto-commit | -| conductor.taskdef.cache.refresh.time.seconds | conductor.mysql.taskDefCacheRefreshInterval | - -* for more properties and default values: https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#application-properties.data.spring.datasource.hikari - -### `postgres-persistence` module (v3.0.0 - v3.0.5): - -| Old | New | Default | -| --- | --- | --- | -| jdbc.url | conductor.postgres.jdbcUrl | jdbc:postgresql://localhost:5432/conductor | -| jdbc.username | conductor.postgres.jdbcUsername | conductor | -| jdbc.password | conductor.postgres.jdbcPassword | password | -| flyway.enabled | conductor.postgres.flywayEnabled | true | -| flyway.table | conductor.postgres.flywayTable | null | -| conductor.postgres.connection.pool.size.max | conductor.postgres.connectionPoolMaxSize | -1 | -| conductor.postgres.connection.pool.idle.min | conductor.postgres.connectionPoolMinIdle | -1 | -| conductor.postgres.connection.lifetime.max | conductor.postgres.connectionMaxLifetime | 30m | -| conductor.postgres.connection.idle.timeout | conductor.postgres.connectionIdleTimeout | 10m | -| conductor.postgres.connection.timeout | conductor.postgres.connectionTimeout | 30s | -| conductor.postgres.transaction.isolation.level | conductor.postgres.transactionIsolationLevel | "" | -| conductor.postgres.autocommit | conductor.postgres.autoCommit | false | -| conductor.taskdef.cache.refresh.time.seconds | conductor.postgres.taskDefCacheRefreshInterval | 60s | - -### `postgres-persistence` module (v3.0.5+): - -| Old | New | -| --- | --- | -| jdbc.url | spring.datasource.url | -| jdbc.username | spring.datasource.username | -| jdbc.password | spring.datasource.password | -| flyway.enabled | spring.flyway.enabled | -| flyway.table | spring.flyway.table | -| conductor.postgres.connection.pool.size.max | spring.datasource.hikari.maximum-pool-size | -| conductor.postgres.connection.pool.idle.min | spring.datasource.hikari.minimum-idle | -| conductor.postgres.connection.lifetime.max | spring.datasource.hikari.max-lifetime | -| conductor.postgres.connection.idle.timeout | spring.datasource.hikari.idle-timeout | -| conductor.postgres.connection.timeout | spring.datasource.hikari.connection-timeout | -| conductor.postgres.transaction.isolation.level | spring.datasource.hikari.transaction-isolation | -| conductor.postgres.autocommit | spring.datasource.hikari.auto-commit | -| conductor.taskdef.cache.refresh.time.seconds | conductor.postgres.taskDefCacheRefreshInterval | - -* for more properties and default values: https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#application-properties.data.spring.datasource.hikari - -### `redis-lock` module: - -| Old | New | Default | -| --- | --- | --- | -| workflow.redis.locking.server.type | conductor.redis-lock.serverType | single | -| workflow.redis.locking.server.address | conductor.redis-lock.serverAddress | redis://127.0.0.1:6379 | -| workflow.redis.locking.server.password | conductor.redis-lock.serverPassword | null | -| workflow.redis.locking.server.master.name | conductor.redis-lock.serverMasterName | master | -| workflow.decider.locking.namespace | conductor.redis-lock.namespace | "" | -| workflow.decider.locking.exceptions.ignore | conductor.redis-lock.ignoreLockingExceptions | false | - -### `redis-persistence` module: - -| Old | New | Default | -| --- | --- | --- | -| EC2_REGION | conductor.redis.dataCenterRegion | us-east-1 | -| EC2_AVAILABILITY_ZONE | conductor.redis.availabilityZone | us-east-1c | -| workflow.dynomite.cluster | _removed_ | -| workflow.dynomite.cluster.name | conductor.redis.clusterName | "" | -| workflow.dynomite.cluster.hosts | conductor.redis.hosts | null | -| workflow.namespace.prefix | conductor.redis.workflowNamespacePrefix | null | -| workflow.namespace.queue.prefix | conductor.redis.queueNamespacePrefix | null | -| workflow.dyno.keyspace.domain | conductor.redis.keyspaceDomain | null | -| workflow.dynomite.connection.maxConnsPerHost | conductor.redis.maxConnectionsPerHost | 10 | -| workflow.dynomite.connection.max.retry.attempt | conductor.redis.maxRetryAttempts | 0 | -| workflow.dynomite.connection.max.timeout.exhausted.ms | conductor.redis.maxTimeoutWhenExhausted | 800ms | -| queues.dynomite.nonQuorum.port | conductor.redis.queuesNonQuorumPort | 22122 | -| workflow.dyno.queue.sharding.strategy | conductor.redis.queueShardingStrategy | roundRobin | -| conductor.taskdef.cache.refresh.time.seconds | conductor.redis.taskDefCacheRefreshInterval | 60s | -| workflow.event.execution.persistence.ttl.seconds | conductor.redis.eventExecutionPersistenceTTL | 60s | - -### `zookeeper-lock` module: - -| Old | New | Default | -| --- | --- | --- | -| workflow.zookeeper.lock.connection | conductor.zookeeper-lock.connectionString | localhost:2181 | -| workflow.zookeeper.lock.sessionTimeoutMs | conductor.zookeeper-lock.sessionTimeout | 60000ms | -| workflow.zookeeper.lock.connectionTimeoutMs | conductor.zookeeper-lock.connectionTimeout | 15000ms | -| workflow.decider.locking.namespace | conductor.zookeeper-lock.namespace | "" | - -### Component configuration: - -| Old | New | Default | -| --- | --- | --- | -| db | conductor.db.type | "" | -| workflow.indexing.enabled | conductor.indexing.enabled | true | -| conductor.disable.async.workers | conductor.system-task-workers.enabled | true | -| decider.sweep.disable | conductor.workflow-reconciler.enabled | true | -| conductor.grpc.server.enabled | conductor.grpc-server.enabled | false | -| workflow.external.payload.storage | conductor.external-payload-storage.type | dummy | -| workflow.default.event.processor.enabled | conductor.default-event-processor.enabled | true | -| workflow.events.default.queue.type | conductor.default-event-queue.type | sqs | -| workflow.status.listener.type | conductor.workflow-status-listener.type | stub | -| - | conductor.task-status-listener.type | stub | -| workflow.decider.locking.server | conductor.workflow-execution-lock.type | noop_lock | -| | | | -| workflow.default.event.queue.enabled | conductor.event-queues.default.enabled | true | -| workflow.sqs.event.queue.enabled | conductor.event-queues.sqs.enabled | false | -| workflow.amqp.event.queue.enabled | conductor.event-queues.amqp.enabled | false | -| workflow.nats.event.queue.enabled | conductor.event-queues.nats.enabled | false | -| workflow.nats_stream.event.queue.enabled | conductor.event-queues.nats-stream.enabled | false | -| | | | -| - | conductor.metrics-logger.enabled | false | -| - | conductor.metrics-prometheus.enabled | false | -| - | conductor.metrics-datadog.enable | false | -| - | conductor.metrics-datadog.api-key | | - diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index b9c30c329..33d0b4d0a 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -1 +1,62 @@ -[Code of Conduct](docs/docs/resources/code-of-conduct.md) \ No newline at end of file +# Code of Conduct + +Hello valued community members! 👋 + +Our Conductor community has grown tremendously, and as part of ensuring a harmonious experience for everyone, +we've outlined some guidelines that we'd love for all members to uphold. +Our community thrives when everyone engages with kindness, respect, and a collaborative spirit. Here's what we hope to see: + + +### 1. Maintain a Positive Tone. +Every interaction is an opportunity to lift someone up. Let's ensure our words and actions reflect optimism and encouragement. + +### 2. Be Respectful to the Community +Every member here comes with a unique background and perspective. Please honor those differences by being courteous, considerate, and open-minded. +Remember, mutual respect is the foundation of a thriving community. Be careful in the words that you choose. +We are a community of professionals, and we conduct ourselves professionally. +Be kind to others. Do not insult or put down other participants. Harassment and other exclusionary behaviors aren't acceptable. +This includes, but is not limited to: +* Violent threats or language directed against another person Discriminatory jokes and language +* Posting sexualized language or imagery +* Posting (or threatening to post) other people's personally identifying information (“doxing”) +* Personal insults, especially those using racist or sexist terms +* Unwelcome sexual attention +* Advocating for, or encouraging, any of the above behavior +* Repeated harassment of others. In general, if someone asks you to stop, then stop + +### 3. Preserve Our Community's Unity +We understand that as we grow, there might be differing opinions and interests. +However, we kindly request not to create splinter groups or fork out the community. +Let's work through our differences and continue building this space together. + +### 4. Focus on Constructive Discussions +We all have moments of frustration, but let's express ourselves in ways that are constructive. +Avoid comments that could come off as sarcastic, condescending, or disdainful. +Remember, it's always possible to give feedback or express disagreement without belittling others. +We are here to learn from each other and make Conductor the best platform out there. +A big part of that are the exchanges of ideas and approaches that are grounded in data and sound reasoning. +We kindly request that you adhere to that pattern and be thoughtful and responsible in your discussions. +This also means that you are required to have discussions focused on the community and not on promotion of any services, products or goods. + +### 5. When we disagree, try to understand why. +Disagreements, both social and technical, happen all the time and this community is no exception. +It is important that we resolve disagreements and differing views constructively. +Remember that we’re all different. The strength of this community comes from its varied community of people from a wide range of backgrounds. +Different people have different perspectives on issues. Being unable to understand why someone holds a viewpoint doesn’t mean that they’re wrong. +Don’t forget that it is human to err and blaming each other doesn’t get us anywhere. +Instead, focus on helping to resolve issues and learning from mistakes. +Our community's strength lies in our collective spirit. +By following these guidelines, we ensure that our community remains an inspiring, respectful, and welcoming place for everyone. +If you have any concerns or suggestions or if you need to report on any behavior that violates this Code of Conduct, please feel free to reach out to the admins - community@orkes.io. +Let's continue to support and uplift each other! + +### Enforcement +We have a variety of ways of enforcing the code of conduct, including, but not limited to +* Asking you nicely to knock it off +* Asking you less nicely +* Temporary or permanent suspension of the account +* Removal of privileges and/or adding restrictions to the account +* Removal of content +* Banning from the community + +Thank you, \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ba24e0019..b102a7a37 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1 +1,60 @@ -[Contributing](docs/docs/resources/contributing.md) \ No newline at end of file +# Contributing +Thanks for your interest in Conductor! +This guide helps to find the most efficient way to contribute, ask questions, and report issues. + +Code of conduct +----- + +Please review our [Code of Conduct](https://orkes.io/orkes-conductor-community-code-of-conduct) + +I have a question! +----- + +We have a dedicated [discussion forum](https://github.com/conductor-oss/conductor/discussions) for asking "how to" questions and to discuss ideas. The discussion forum is a great place to start if you're considering creating a feature request or work on a Pull Request. +*Please do not create issues to ask questions.* + +Conductor users hangout in the [Slack channel](https://join.slack.com/t/orkes-conductor/shared_invite/zt-xyxqyseb-YZ3hwwAgHJH97bsrYRnSZg). Join the channel for more real-time communication! + +I want to contribute! +------ + +We welcome Pull Requests and already had many outstanding community contributions! +Creating and reviewing Pull Requests take considerable time. This section helps you to set up a smooth Pull Request experience. + +The stable branch is [main](https://github.com/conductor-oss/conductor/tree/main). + +Please create pull requests for your contributions against [main](https://github.com/conductor-oss/conductor/tree/main) only. + +It's a great idea to discuss the new feature you're considering on the [discussion forum](https://github.com/conductor-oss/conductor/discussions) before writing any code. There are often different ways you can implement a feature. Getting some discussion about different options helps shape the best solution. When starting directly with a Pull Request, there is the risk of having to make considerable changes. Sometimes that is the best approach, though! Showing an idea with code can be very helpful; be aware that it might be throw-away work. Some of our best Pull Requests came out of multiple competing implementations, which helped shape it to perfection. + +Also, consider that not every feature is a good fit for Conductor. A few things to consider are: + +* Is it increasing complexity for the user, or might it be confusing? +* Does it, in any way, break backward compatibility (this is seldom acceptable) +* Does it require new dependencies (this is rarely acceptable for core modules) +* Should the feature be opt-in or enabled by default. For integration with a new Queuing recipe or persistence module, a separate module which can be optionally enabled is the right choice. +* Should the feature be implemented in the main Conductor repository, or would it be better to set up a separate repository? Especially for integration with other systems, a separate repository is often the right choice because the life-cycle of it will be different. +* Is it part of the Conductor project roadmap? + +Of course, for more minor bug fixes and improvements, the process can be more light-weight. + +We'll try to be responsive to Pull Requests. Do keep in mind that because of the inherently distributed nature of open source projects, responses to a PR might take some time because of time zones, weekends, and other things we may be working on. + +I want to report an issue +----- + +If you found a bug, it is much appreciated if you create an issue. Please include clear instructions on how to reproduce the issue, or even better, include a test case on a branch. Make sure to come up with a descriptive title for the issue because this helps while organizing issues. + +I have a great idea for a new feature +---- +Many features in Conductor have come from ideas from the community. If you think something is missing or certain use cases could be supported better, let us know! You can do so by opening a discussion on the [discussion forum](https://github.com/conductor-oss/conductor/discussions). Provide as much relevant context to why and when the feature would be helpful. Providing context is especially important for "Support XYZ" issues since we might not be familiar with what "XYZ" is and why it's useful. If you have an idea of how to implement the feature, include that as well. + +Once we have decided on a direction, it's time to summarize the idea by creating a new issue. + +## Code Style +We use [spotless](https://github.com/diffplug/spotless) to enforce consistent code style for the project, so make sure to run `gradlew spotlessApply` to fix any violations after code changes. + +## License +All files are released with the Apache 2.0 license. + + diff --git a/LICENSE b/LICENSE index 6a1d025d8..78ae7ea62 100644 --- a/LICENSE +++ b/LICENSE @@ -186,7 +186,7 @@ Apache License same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright {yyyy} Netflix, Inc. + Copyright {yyyy} Orkes, Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/README.md b/README.md index 0d24f3066..2fd5c8153 100644 --- a/README.md +++ b/README.md @@ -1,24 +1,7 @@ -![Conductor](docs/docs/img/logo.png) +![Conductor](docs/img/logo.svg) -## Announcement - -> Effective **December 13, 2023**, Netflix will discontinue maintenance of Conductor OSS on GitHub. This strategic decision, while difficult, is essential for realigning our resources to better serve our business objectives with our internal Conductor fork. -> -> We are *deeply grateful* for your support and contributions over the years. While Netflix will no longer be maintaining this repo, members of the Conductor community have been active in promoting alternative forks of this project, we’ll leave the code as is and trust that the health of the community will remain strong and continue to develop moving forward. - - -# Conductor -[![NetflixOSS Lifecycle](https://img.shields.io/osslifecycle/Netflix/conductor.svg)]() -[![Github release](https://img.shields.io/github/v/release/Netflix/conductor.svg)](https://GitHub.com/Netflix/conductor/releases) -[![License](https://img.shields.io/github/license/Netflix/conductor.svg)](http://www.apache.org/licenses/LICENSE-2.0) - -[![GitHub stars](https://img.shields.io/github/stars/Netflix/conductor.svg?style=social&label=Star&maxAge=2592000)](https://GitHub.com/Netflix/conductor/stargazers/) -[![GitHub forks](https://img.shields.io/github/forks/Netflix/conductor.svg?style=social&label=Fork&maxAge=2592000)](https://GitHub.com/Netflix/conductor/network/) - -Conductor is a platform created by Netflix to orchestrate workflows that span across microservices. - -## Releases -The final release is [![Github release](https://img.shields.io/github/v/release/Netflix/conductor.svg)](https://GitHub.com/Netflix/conductor/releases) +[![Github release](https://img.shields.io/github/v/release/conductor-oss/conductor.svg)](https://GitHub.com/Netflix/conductor-oss/releases) +[![License](https://img.shields.io/github/license/conductor-oss/conductor.svg)](http://www.apache.org/licenses/LICENSE-2.0) ## Workflow Creation in Code Conductor supports creating workflows using JSON and Code. @@ -63,37 +46,80 @@ Binaries are available from the [Maven Central Repository](https://search.maven. | conductor-grpc-client | gRPC client to interact with the gRPC server | | conductor-grpc-server | gRPC server Application | | conductor-test-harness | Integration and regression tests | +Conductor is a platform _originally_ created at Netflix to orchestrate microservices and events. +Conductor OSS is maintained by the team of developers at [Orkes](https://orkes.io/) along with the members of the open source community. + +The latest version is [![Github release](https://img.shields.io/github/v/release/conductor-oss/conductor.svg)](https://GitHub.com/conductor-oss/conductor/releases) +## Conductor OSS +This is the new home for the Conductor open source going forward (previously hosted at Netflix/Conductor). + +_The last published version of Netflix Conductor will be **3.15.0** which we will continue to support._ + +If you would like to participate in the roadmap and development, [please reach out](https://forms.gle/P2i1xHrxPQLrjzTB7). + +## ⭐ This repository +Show support for the Conductor OSS. Please help spread the awareness by starring this repo. + +[![GitHub stars](https://img.shields.io/github/stars/conductor-oss/conductor.svg?style=social&label=Star&maxAge=)](https://GitHub.com/conductor-oss/conductor/) + +## Getting Started + +### Using Docker (Recommended) +Follow the steps below to launch the docker container: + +```shell +docker compose -f docker/docker-compose.yaml up +``` +* Navigate to http://localhost:5000 once the container starts to launch UI. +* APIs are accessible at http://localhost:8080 +* Swagger Docs:http://localhost:8080/swagger-ui/index.html?configUrl=/api-docs/swagger-config#/ ## Database Requirements * The default persistence used is Redis -* The indexing backend is [Elasticsearch](https://www.elastic.co/) (6.x) +* The indexing backend is [Elasticsearch](https://www.elastic.co/) (7.x) + +## Configuration for various database backends + +| Backend | Configuration | +|----------------|---------------------------------------------------------------------------------------| +| Redis + ES7 | [config-redis.properties](docker/server/config/config-redis.properties) | +| Postgres | [config-postgres.properties](docker/server/config/config-postgres.properties) | +| Postgres + ES7 | [config-postgres-es7.properties](docker/server/config/config-postgres-es7.properties) | +| MySQL + ES7 | [config-mysql.properties](docker/server/config/config-mysql.properties) | ## Other Requirements * JDK 17+ -* UI requires Node 14 to build. Earlier Node versions may work but is untested. +* UI requires Node 14 to build. Earlier Node versions may work but are untested. -## Get Support -There are several ways to get in touch with us: -* [Slack Community](https://join.slack.com/t/orkes-conductor/shared_invite/zt-xyxqyseb-YZ3hwwAgHJH97bsrYRnSZg) -* [GitHub Discussion Forum](https://github.com/Netflix/conductor/discussions) +### Building From Source +If you wish to build your own distribution, you can run ```./gradlew build``` from this project that products the runtime artifacts. +The runnable server is in server/ module. + +## Conductor OSS Roadmap +[See the roadmap for the Conductor](ROADMAP.md) + +## Resources +#### [Slack Community](https://join.slack.com/t/orkes-conductor/shared_invite/zt-2hmxn0i3n-_W~a9rWMbvMoYmlJo3Y15g) +We have an active [community](https://join.slack.com/t/orkes-conductor/shared_invite/zt-2hmxn0i3n-_W~a9rWMbvMoYmlJo3Y15g) of Conductor users and contributors on the channel. +#### [Documentation Site](https://docs.conductor-oss.org/) +[Documentation](https://docs.conductor-oss.org/) and tutorial on how to use Conductor + +[Discussion Forum](https://github.com/conductor-oss/conductor/discussions): Please use the forum for questions and discussing ideas and join the community. + +### Conductor SDKs +Conductor supports creating workflows using JSON and Code. +SDK support for creating workflows using code is available in multiple languages and can be found at https://github.com/conductor-sdk -## Contributions -Whether it is a small documentation correction, bug fix or a new feature, contributions are highly appreciated. We just ask you to follow standard OSS guidelines. The [Discussion Forum](https://github.com/Netflix/conductor/discussions) is a good place to ask questions, discuss new features and explore ideas. Please check with us before spending too much time, only to find out later that someone else is already working on a similar feature. -`main` branch is the current working branch. Please send your PR's to `main` branch, making sure that it builds on your local system successfully. Also, please make sure all the conflicts are resolved. -## License -Copyright 2022 Netflix, Inc. -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at +## Get Support +There are several ways to get in touch with us: +* [Slack Community](https://join.slack.com/t/orkes-conductor/shared_invite/zt-xyxqyseb-YZ3hwwAgHJH97bsrYRnSZg) - http://www.apache.org/licenses/LICENSE-2.0 +## Contributors -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. + + + diff --git a/RELATED.md b/RELATED.md index b7adabea3..abd0cf105 100644 --- a/RELATED.md +++ b/RELATED.md @@ -1 +1 @@ -[Related Projects](docs/docs/resources/related.md) +[Related Projects](docs/resources/related.md) diff --git a/ROADMAP.md b/ROADMAP.md new file mode 100644 index 000000000..35d01abe2 --- /dev/null +++ b/ROADMAP.md @@ -0,0 +1,75 @@ +# Conductor OSS Roadmap + + +## New Features +### Type safety for workflow inputs and task input/output through JSON Schema + +* Allow type safe workflows and workers with support for JSON schema and protobuf +* Enable scaffolding code generation for workers through schema for workers using CLI tool + +### New System Tasks + +* Database task to work with relational & no-sql databases +* Polling support for HTTP task +* Operators + * * For..Each with parallel and sequential execution + * * Improved While loop + * * Try..Catch for improved error handling at the task level + +### LLM Integrations +Conductor is a perfect platform to build your next LLM powered application or incorporating genAI into your applications. +Enable system tasks for LLM integrations that lets you work with various language models for: +1. Text completion +2. Chat completion with memory +3. Embedding generation + +### CLI for Conductor +Allow developers to manage their conductor instance via CLI. + +* Manage metadata +* Query and manage workflow executions (terminate, pause, resume, retry) +* Start | Stop manage conductor server + +### Support Python as a scripting language for INLINE task +Extend usability of Conductor by allowing lightweight python code as INLINE tasks. + +### New APIs for workflow state management + +* Synchronous execution of workflows +* update workflow variables +* Update tasks synchronously + +## SDKs + +* Rust +* Kotlin +* C++ +* Ruby +* Swift +* Flutter / Dart +* PHP + +### Worker metrics on server +Expose an endpoint on the server that can be used by workers to publish worker specific metrics. +This will allow monitoring metrics for all the workers in a distributed system across the entire system. + +## Testing +Infrastructure to make workflows easier to test and debug right from the UI and IDE. + +### Workflow Debugger + +* Ability to debug your workflows during development just like you would do when you write code +* All functionality of a debugger +* Breakpoints add/remove +* Step to next +* Drop to a certain task that was already executed. (going back in time) +* Ability to inspect, modify, add input / output parameters +* Watch Windows to see values of interesting  parameters during execution +* Attaching to a certain WF execution +* Remote Task debugging (with SDK Support).. Enable step by step execution in a task worker from the server + +## Maintenance + +1. Deprecate support for Elasticsearch 6 +2. Update support for newer versions of Elasticsearch +2. Improve/Fix JOIN task performance (less about making it performant and more about just fixing the usability)  - Done \ No newline at end of file diff --git a/SECURITY.md b/SECURITY.md index 80978ee5b..7afa91969 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -10,4 +10,4 @@ ## Reporting a Vulnerability -Please email conductor@netflix.com to report vulnerabilities. +Please email oss@orkes.com to report vulnerabilities. diff --git a/amqp/build.gradle b/amqp/build.gradle new file mode 100644 index 000000000..ffa9ea735 --- /dev/null +++ b/amqp/build.gradle @@ -0,0 +1,12 @@ +dependencies { + implementation project(':conductor-common') + implementation project(':conductor-core') + + implementation "com.rabbitmq:amqp-client:${revAmqpClient}" + implementation "org.apache.commons:commons-lang3:" + implementation "com.google.guava:guava:${revGuava}" + implementation "io.reactivex:rxjava:${revRxJava}" + + compileOnly 'org.springframework.boot:spring-boot-starter' + compileOnly 'org.springframework.boot:spring-boot-starter-web' +} \ No newline at end of file diff --git a/amqp/src/main/java/com/netflix/conductor/contribs/queue/amqp/AMQPConnection.java b/amqp/src/main/java/com/netflix/conductor/contribs/queue/amqp/AMQPConnection.java new file mode 100644 index 000000000..d5839539a --- /dev/null +++ b/amqp/src/main/java/com/netflix/conductor/contribs/queue/amqp/AMQPConnection.java @@ -0,0 +1,391 @@ +/* + * Copyright 2023 Conductor Authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package com.netflix.conductor.contribs.queue.amqp; + +import java.io.IOException; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.TimeoutException; +import java.util.stream.Collectors; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.netflix.conductor.contribs.queue.amqp.config.AMQPRetryPattern; +import com.netflix.conductor.contribs.queue.amqp.util.AMQPConstants; +import com.netflix.conductor.contribs.queue.amqp.util.ConnectionType; + +import com.rabbitmq.client.Address; +import com.rabbitmq.client.BlockedListener; +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.Connection; +import com.rabbitmq.client.ConnectionFactory; +import com.rabbitmq.client.ShutdownListener; +import com.rabbitmq.client.ShutdownSignalException; + +public class AMQPConnection { + + private static Logger LOGGER = LoggerFactory.getLogger(AMQPConnection.class); + private volatile Connection publisherConnection = null; + private volatile Connection subscriberConnection = null; + private ConnectionFactory factory = null; + private Address[] addresses = null; + private static AMQPConnection amqpConnection = null; + private static final String PUBLISHER = "Publisher"; + private static final String SUBSCRIBER = "Subscriber"; + private static final Map> availableChannelPool = + new ConcurrentHashMap>(); + private static final Map subscriberReservedChannelPool = + new ConcurrentHashMap(); + private static AMQPRetryPattern retrySettings = null; + + private AMQPConnection() {} + + private AMQPConnection(final ConnectionFactory factory, final Address[] address) { + this.factory = factory; + this.addresses = address; + } + + public static synchronized AMQPConnection getInstance( + final ConnectionFactory factory, + final Address[] address, + final AMQPRetryPattern retrySettings) { + if (AMQPConnection.amqpConnection == null) { + AMQPConnection.amqpConnection = new AMQPConnection(factory, address); + } + AMQPConnection.retrySettings = retrySettings; + return AMQPConnection.amqpConnection; + } + + // Exposed for UT + public static void setAMQPConnection(AMQPConnection amqpConnection) { + AMQPConnection.amqpConnection = amqpConnection; + } + + public Address[] getAddresses() { + return addresses; + } + + private Connection createConnection(String connectionPrefix) { + int retryIndex = 1; + while (true) { + try { + Connection connection = + factory.newConnection( + addresses, System.getenv("HOSTNAME") + "-" + connectionPrefix); + if (connection == null || !connection.isOpen()) { + throw new RuntimeException("Failed to open connection"); + } + connection.addShutdownListener( + new ShutdownListener() { + @Override + public void shutdownCompleted(ShutdownSignalException cause) { + LOGGER.error( + "Received a shutdown exception for the connection {}. reason {} cause{}", + connection.getClientProvidedName(), + cause.getMessage(), + cause); + } + }); + connection.addBlockedListener( + new BlockedListener() { + @Override + public void handleUnblocked() throws IOException { + LOGGER.info( + "Connection {} is unblocked", + connection.getClientProvidedName()); + } + + @Override + public void handleBlocked(String reason) throws IOException { + LOGGER.error( + "Connection {} is blocked. reason: {}", + connection.getClientProvidedName(), + reason); + } + }); + return connection; + } catch (final IOException e) { + AMQPRetryPattern retry = retrySettings; + if (retry == null) { + final String error = + "IO error while connecting to " + + Arrays.stream(addresses) + .map(address -> address.toString()) + .collect(Collectors.joining(",")); + LOGGER.error(error, e); + throw new RuntimeException(error, e); + } + try { + retry.continueOrPropogate(e, retryIndex); + } catch (Exception ex) { + final String error = + "Retries completed. IO error while connecting to " + + Arrays.stream(addresses) + .map(address -> address.toString()) + .collect(Collectors.joining(",")); + LOGGER.error(error, e); + throw new RuntimeException(error, e); + } + retryIndex++; + } catch (final TimeoutException e) { + AMQPRetryPattern retry = retrySettings; + if (retry == null) { + final String error = + "Timeout while connecting to " + + Arrays.stream(addresses) + .map(address -> address.toString()) + .collect(Collectors.joining(",")); + LOGGER.error(error, e); + throw new RuntimeException(error, e); + } + try { + retry.continueOrPropogate(e, retryIndex); + } catch (Exception ex) { + final String error = + "Retries completed. Timeout while connecting to " + + Arrays.stream(addresses) + .map(address -> address.toString()) + .collect(Collectors.joining(",")); + LOGGER.error(error, e); + throw new RuntimeException(error, e); + } + retryIndex++; + } + } + } + + public Channel getOrCreateChannel(ConnectionType connectionType, String queueOrExchangeName) + throws Exception { + LOGGER.debug( + "Accessing the channel for queueOrExchange {} with type {} ", + queueOrExchangeName, + connectionType); + switch (connectionType) { + case SUBSCRIBER: + String subChnName = connectionType + ";" + queueOrExchangeName; + if (subscriberReservedChannelPool.containsKey(subChnName)) { + Channel locChn = subscriberReservedChannelPool.get(subChnName); + if (locChn != null && locChn.isOpen()) { + return locChn; + } + } + synchronized (this) { + if (subscriberConnection == null || !subscriberConnection.isOpen()) { + subscriberConnection = createConnection(SUBSCRIBER); + } + } + Channel subChn = borrowChannel(connectionType, subscriberConnection); + // Add the subscribed channels to Map to avoid messages being acknowledged on + // different from the subscribed one + subscriberReservedChannelPool.put(subChnName, subChn); + return subChn; + case PUBLISHER: + synchronized (this) { + if (publisherConnection == null || !publisherConnection.isOpen()) { + publisherConnection = createConnection(PUBLISHER); + } + } + return borrowChannel(connectionType, publisherConnection); + default: + return null; + } + } + + private Channel getOrCreateChannel(ConnectionType connType, Connection rmqConnection) { + // Channel creation is required + Channel locChn = null; + int retryIndex = 1; + while (true) { + try { + LOGGER.debug("Creating a channel for " + connType); + locChn = rmqConnection.createChannel(); + if (locChn == null || !locChn.isOpen()) { + throw new RuntimeException("Fail to open " + connType + " channel"); + } + locChn.addShutdownListener( + cause -> { + LOGGER.error( + connType + " Channel has been shutdown: {}", + cause.getMessage(), + cause); + }); + return locChn; + } catch (final IOException e) { + AMQPRetryPattern retry = retrySettings; + if (retry == null) { + throw new RuntimeException( + "Cannot open " + + connType + + " channel on " + + Arrays.stream(addresses) + .map(address -> address.toString()) + .collect(Collectors.joining(",")), + e); + } + try { + retry.continueOrPropogate(e, retryIndex); + } catch (Exception ex) { + throw new RuntimeException( + "Retries completed. Cannot open " + + connType + + " channel on " + + Arrays.stream(addresses) + .map(address -> address.toString()) + .collect(Collectors.joining(",")), + e); + } + retryIndex++; + } catch (final Exception e) { + AMQPRetryPattern retry = retrySettings; + if (retry == null) { + throw new RuntimeException( + "Cannot open " + + connType + + " channel on " + + Arrays.stream(addresses) + .map(address -> address.toString()) + .collect(Collectors.joining(",")), + e); + } + try { + retry.continueOrPropogate(e, retryIndex); + } catch (Exception ex) { + throw new RuntimeException( + "Retries completed. Cannot open " + + connType + + " channel on " + + Arrays.stream(addresses) + .map(address -> address.toString()) + .collect(Collectors.joining(",")), + e); + } + retryIndex++; + } + } + } + + public void close() { + LOGGER.info("Closing all connections and channels"); + try { + closeChannelsInMap(ConnectionType.PUBLISHER); + closeChannelsInMap(ConnectionType.SUBSCRIBER); + closeConnection(publisherConnection); + closeConnection(subscriberConnection); + } finally { + availableChannelPool.clear(); + publisherConnection = null; + subscriberConnection = null; + } + } + + private void closeChannelsInMap(ConnectionType conType) { + Set channels = availableChannelPool.get(conType); + if (channels != null && !channels.isEmpty()) { + Iterator itr = channels.iterator(); + while (itr.hasNext()) { + Channel channel = itr.next(); + closeChannel(channel); + } + channels.clear(); + } + } + + private void closeConnection(Connection connection) { + if (connection == null || !connection.isOpen()) { + LOGGER.warn("Connection is null or closed already. Not closing it again"); + } else { + try { + connection.close(); + } catch (Exception e) { + LOGGER.warn("Fail to close connection: {}", e.getMessage(), e); + } + } + } + + private void closeChannel(Channel channel) { + if (channel == null || !channel.isOpen()) { + LOGGER.warn("Channel is null or closed already. Not closing it again"); + } else { + try { + channel.close(); + } catch (Exception e) { + LOGGER.warn("Fail to close channel: {}", e.getMessage(), e); + } + } + } + + /** + * Gets the channel for specified connectionType. + * + * @param connectionType holds the multiple channels for different connection types for thread + * safe operation. + * @param rmqConnection publisher or subscriber connection instance + * @return channel instance + * @throws Exception + */ + private synchronized Channel borrowChannel( + ConnectionType connectionType, Connection rmqConnection) throws Exception { + if (!availableChannelPool.containsKey(connectionType)) { + Channel channel = getOrCreateChannel(connectionType, rmqConnection); + LOGGER.info(String.format(AMQPConstants.INFO_CHANNEL_CREATION_SUCCESS, connectionType)); + return channel; + } + Set channels = availableChannelPool.get(connectionType); + if (channels != null && channels.isEmpty()) { + Channel channel = getOrCreateChannel(connectionType, rmqConnection); + LOGGER.info(String.format(AMQPConstants.INFO_CHANNEL_CREATION_SUCCESS, connectionType)); + return channel; + } + Iterator itr = channels.iterator(); + while (itr.hasNext()) { + Channel channel = itr.next(); + if (channel != null && channel.isOpen()) { + itr.remove(); + LOGGER.info( + String.format(AMQPConstants.INFO_CHANNEL_BORROW_SUCCESS, connectionType)); + return channel; + } else { + itr.remove(); + } + } + Channel channel = getOrCreateChannel(connectionType, rmqConnection); + LOGGER.info(String.format(AMQPConstants.INFO_CHANNEL_RESET_SUCCESS, connectionType)); + return channel; + } + + /** + * Returns the channel to connection pool for specified connectionType. + * + * @param connectionType + * @param channel + * @throws Exception + */ + public synchronized void returnChannel(ConnectionType connectionType, Channel channel) + throws Exception { + if (channel == null || !channel.isOpen()) { + channel = null; // channel is reset. + } + Set channels = availableChannelPool.get(connectionType); + if (channels == null) { + channels = new HashSet(); + availableChannelPool.put(connectionType, channels); + } + channels.add(channel); + LOGGER.info(String.format(AMQPConstants.INFO_CHANNEL_RETURN_SUCCESS, connectionType)); + } +} diff --git a/amqp/src/main/java/com/netflix/conductor/contribs/queue/amqp/AMQPObservableQueue.java b/amqp/src/main/java/com/netflix/conductor/contribs/queue/amqp/AMQPObservableQueue.java new file mode 100644 index 000000000..c71850eb0 --- /dev/null +++ b/amqp/src/main/java/com/netflix/conductor/contribs/queue/amqp/AMQPObservableQueue.java @@ -0,0 +1,864 @@ +/* + * Copyright 2023 Conductor Authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package com.netflix.conductor.contribs.queue.amqp; + +import java.io.IOException; +import java.security.KeyManagementException; +import java.security.NoSuchAlgorithmException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; + +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.netflix.conductor.contribs.queue.amqp.config.AMQPEventQueueProperties; +import com.netflix.conductor.contribs.queue.amqp.config.AMQPRetryPattern; +import com.netflix.conductor.contribs.queue.amqp.util.AMQPConstants; +import com.netflix.conductor.contribs.queue.amqp.util.AMQPSettings; +import com.netflix.conductor.contribs.queue.amqp.util.ConnectionType; +import com.netflix.conductor.core.events.queue.Message; +import com.netflix.conductor.core.events.queue.ObservableQueue; +import com.netflix.conductor.metrics.Monitors; + +import com.google.common.collect.Maps; +import com.rabbitmq.client.AMQP; +import com.rabbitmq.client.Address; +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.ConnectionFactory; +import com.rabbitmq.client.Consumer; +import com.rabbitmq.client.DefaultConsumer; +import com.rabbitmq.client.Envelope; +import com.rabbitmq.client.GetResponse; +import rx.Observable; +import rx.Subscriber; + +/** + * @author Ritu Parathody + */ +public class AMQPObservableQueue implements ObservableQueue { + + private static final Logger LOGGER = LoggerFactory.getLogger(AMQPObservableQueue.class); + + private final AMQPSettings settings; + private final AMQPRetryPattern retrySettings; + private final String QUEUE_TYPE = "x-queue-type"; + private final int batchSize; + private final boolean useExchange; + private int pollTimeInMS; + private AMQPConnection amqpConnection; + + protected LinkedBlockingQueue messages = new LinkedBlockingQueue<>(); + private volatile boolean running; + + public AMQPObservableQueue( + ConnectionFactory factory, + Address[] addresses, + boolean useExchange, + AMQPSettings settings, + AMQPRetryPattern retrySettings, + int batchSize, + int pollTimeInMS) { + if (factory == null) { + throw new IllegalArgumentException("Connection factory is undefined"); + } + if (addresses == null || addresses.length == 0) { + throw new IllegalArgumentException("Addresses are undefined"); + } + if (settings == null) { + throw new IllegalArgumentException("Settings are undefined"); + } + if (batchSize <= 0) { + throw new IllegalArgumentException("Batch size must be greater than 0"); + } + if (pollTimeInMS <= 0) { + throw new IllegalArgumentException("Poll time must be greater than 0 ms"); + } + this.useExchange = useExchange; + this.settings = settings; + this.batchSize = batchSize; + this.amqpConnection = AMQPConnection.getInstance(factory, addresses, retrySettings); + this.retrySettings = retrySettings; + this.setPollTimeInMS(pollTimeInMS); + } + + @Override + public Observable observe() { + Observable.OnSubscribe onSubscribe = null; + // This will enabled the messages to be processed one after the other as per the + // observable next behavior. + if (settings.isSequentialProcessing()) { + LOGGER.info("Subscribing for the message processing on schedule basis"); + receiveMessages(); + onSubscribe = + subscriber -> { + Observable interval = + Observable.interval(pollTimeInMS, TimeUnit.MILLISECONDS); + interval.flatMap( + (Long x) -> { + if (!isRunning()) { + LOGGER.debug( + "Component stopped, skip listening for messages from RabbitMQ"); + return Observable.from(Collections.emptyList()); + } else { + List available = new LinkedList<>(); + messages.drainTo(available); + + if (!available.isEmpty()) { + AtomicInteger count = new AtomicInteger(0); + StringBuilder buffer = new StringBuilder(); + available.forEach( + msg -> { + buffer.append(msg.getId()) + .append("=") + .append(msg.getPayload()); + count.incrementAndGet(); + + if (count.get() + < available.size()) { + buffer.append(","); + } + }); + LOGGER.info( + String.format( + "Batch from %s to conductor is %s", + settings + .getQueueOrExchangeName(), + buffer.toString())); + } + return Observable.from(available); + } + }) + .subscribe(subscriber::onNext, subscriber::onError); + }; + LOGGER.info("Subscribed for the message processing on schedule basis"); + } else { + onSubscribe = + subscriber -> { + LOGGER.info("Subscribing for the event based AMQP message processing"); + receiveMessages(subscriber); + LOGGER.info("Subscribed for the event based AMQP message processing"); + }; + } + return Observable.create(onSubscribe); + } + + @Override + public String getType() { + return useExchange ? AMQPConstants.AMQP_EXCHANGE_TYPE : AMQPConstants.AMQP_QUEUE_TYPE; + } + + @Override + public String getName() { + return settings.getEventName(); + } + + @Override + public String getURI() { + return settings.getQueueOrExchangeName(); + } + + public int getBatchSize() { + return batchSize; + } + + public AMQPSettings getSettings() { + return settings; + } + + public Address[] getAddresses() { + return amqpConnection.getAddresses(); + } + + public List ack(List messages) { + final List failedMessages = new ArrayList<>(); + for (final Message message : messages) { + try { + ackMsg(message); + } catch (final Exception e) { + LOGGER.error("Cannot ACK message with delivery tag {}", message.getReceipt(), e); + failedMessages.add(message.getReceipt()); + } + } + return failedMessages; + } + + public void ackMsg(Message message) throws Exception { + int retryIndex = 1; + while (true) { + try { + LOGGER.info("ACK message with delivery tag {}", message.getReceipt()); + Channel chn = + amqpConnection.getOrCreateChannel( + ConnectionType.SUBSCRIBER, getSettings().getQueueOrExchangeName()); + chn.basicAck(Long.parseLong(message.getReceipt()), false); + LOGGER.info("Ack'ed the message with delivery tag {}", message.getReceipt()); + break; + } catch (final Exception e) { + AMQPRetryPattern retry = retrySettings; + if (retry == null) { + LOGGER.error( + "Cannot ACK message with delivery tag {}", message.getReceipt(), e); + throw e; + } + try { + retry.continueOrPropogate(e, retryIndex); + } catch (Exception ex) { + LOGGER.error( + "Retries completed. Cannot ACK message with delivery tag {}", + message.getReceipt(), + e); + throw ex; + } + retryIndex++; + } + } + } + + @Override + public void nack(List messages) { + for (final Message message : messages) { + int retryIndex = 1; + while (true) { + try { + LOGGER.info("NACK message with delivery tag {}", message.getReceipt()); + Channel chn = + amqpConnection.getOrCreateChannel( + ConnectionType.SUBSCRIBER, + getSettings().getQueueOrExchangeName()); + chn.basicNack(Long.parseLong(message.getReceipt()), false, false); + LOGGER.info("Nack'ed the message with delivery tag {}", message.getReceipt()); + break; + } catch (final Exception e) { + AMQPRetryPattern retry = retrySettings; + if (retry == null) { + LOGGER.error( + "Cannot NACK message with delivery tag {}", + message.getReceipt(), + e); + } + try { + retry.continueOrPropogate(e, retryIndex); + } catch (Exception ex) { + LOGGER.error( + "Retries completed. Cannot NACK message with delivery tag {}", + message.getReceipt(), + e); + break; + } + retryIndex++; + } + } + } + } + + private static AMQP.BasicProperties buildBasicProperties( + final Message message, final AMQPSettings settings) { + return new AMQP.BasicProperties.Builder() + .messageId( + StringUtils.isEmpty(message.getId()) + ? UUID.randomUUID().toString() + : message.getId()) + .correlationId( + StringUtils.isEmpty(message.getReceipt()) + ? UUID.randomUUID().toString() + : message.getReceipt()) + .contentType(settings.getContentType()) + .contentEncoding(settings.getContentEncoding()) + .deliveryMode(settings.getDeliveryMode()) + .build(); + } + + private void publishMessage(Message message, String exchange, String routingKey) { + Channel chn = null; + int retryIndex = 1; + while (true) { + try { + final String payload = message.getPayload(); + chn = + amqpConnection.getOrCreateChannel( + ConnectionType.PUBLISHER, getSettings().getQueueOrExchangeName()); + chn.basicPublish( + exchange, + routingKey, + buildBasicProperties(message, settings), + payload.getBytes(settings.getContentEncoding())); + LOGGER.info(String.format("Published message to %s: %s", exchange, payload)); + break; + } catch (Exception ex) { + AMQPRetryPattern retry = retrySettings; + if (retry == null) { + LOGGER.error( + "Failed to publish message {} to {}", + message.getPayload(), + exchange, + ex); + throw new RuntimeException(ex); + } + try { + retry.continueOrPropogate(ex, retryIndex); + } catch (Exception e) { + LOGGER.error( + "Retries completed. Failed to publish message {} to {}", + message.getPayload(), + exchange, + ex); + throw new RuntimeException(ex); + } + retryIndex++; + } finally { + if (chn != null) { + try { + amqpConnection.returnChannel(ConnectionType.PUBLISHER, chn); + } catch (Exception e) { + LOGGER.error( + "Failed to return the channel of {}. {}", + ConnectionType.PUBLISHER, + e); + } + } + } + } + } + + @Override + public void publish(List messages) { + try { + final String exchange, routingKey; + if (useExchange) { + // Use exchange + routing key for publishing + getOrCreateExchange( + ConnectionType.PUBLISHER, + settings.getQueueOrExchangeName(), + settings.getExchangeType(), + settings.isDurable(), + settings.autoDelete(), + settings.getArguments()); + exchange = settings.getQueueOrExchangeName(); + routingKey = settings.getRoutingKey(); + } else { + // Use queue for publishing + final AMQP.Queue.DeclareOk declareOk = + getOrCreateQueue( + ConnectionType.PUBLISHER, + settings.getQueueOrExchangeName(), + settings.isDurable(), + settings.isExclusive(), + settings.autoDelete(), + settings.getArguments()); + exchange = StringUtils.EMPTY; // Empty exchange name for queue + routingKey = declareOk.getQueue(); // Routing name is the name of queue + } + messages.forEach(message -> publishMessage(message, exchange, routingKey)); + } catch (final RuntimeException ex) { + throw ex; + } catch (final Exception ex) { + LOGGER.error("Failed to publish messages: {}", ex.getMessage(), ex); + throw new RuntimeException(ex); + } + } + + @Override + public void setUnackTimeout(Message message, long unackTimeout) { + throw new UnsupportedOperationException(); + } + + @Override + public long size() { + Channel chn = null; + try { + chn = + amqpConnection.getOrCreateChannel( + ConnectionType.SUBSCRIBER, getSettings().getQueueOrExchangeName()); + return chn.messageCount(settings.getQueueOrExchangeName()); + } catch (final Exception e) { + throw new RuntimeException(e); + } finally { + if (chn != null) { + try { + amqpConnection.returnChannel(ConnectionType.SUBSCRIBER, chn); + } catch (Exception e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + } + } + + @Override + public void close() { + amqpConnection.close(); + } + + @Override + public void start() { + LOGGER.info( + "Started listening to {}:{}", + getClass().getSimpleName(), + settings.getQueueOrExchangeName()); + running = true; + } + + @Override + public void stop() { + LOGGER.info( + "Stopped listening to {}:{}", + getClass().getSimpleName(), + settings.getQueueOrExchangeName()); + running = false; + } + + @Override + public boolean isRunning() { + return running; + } + + public static class Builder { + + private final Address[] addresses; + private final int batchSize; + private final int pollTimeInMS; + private final ConnectionFactory factory; + private final AMQPEventQueueProperties properties; + + public Builder(AMQPEventQueueProperties properties) { + this.properties = properties; + this.addresses = buildAddressesFromHosts(); + this.factory = buildConnectionFactory(); + // messages polling settings + this.batchSize = properties.getBatchSize(); + this.pollTimeInMS = (int) properties.getPollTimeDuration().toMillis(); + } + + private Address[] buildAddressesFromHosts() { + // Read hosts from config + final String hosts = properties.getHosts(); + if (StringUtils.isEmpty(hosts)) { + throw new IllegalArgumentException("Hosts are undefined"); + } + return Address.parseAddresses(hosts); + } + + private ConnectionFactory buildConnectionFactory() { + final ConnectionFactory factory = new ConnectionFactory(); + // Get rabbitmq username from config + final String username = properties.getUsername(); + if (StringUtils.isEmpty(username)) { + throw new IllegalArgumentException("Username is null or empty"); + } else { + factory.setUsername(username); + } + // Get rabbitmq password from config + final String password = properties.getPassword(); + if (StringUtils.isEmpty(password)) { + throw new IllegalArgumentException("Password is null or empty"); + } else { + factory.setPassword(password); + } + // Get vHost from config + final String virtualHost = properties.getVirtualHost(); + ; + if (StringUtils.isEmpty(virtualHost)) { + throw new IllegalArgumentException("Virtual host is null or empty"); + } else { + factory.setVirtualHost(virtualHost); + } + // Get server port from config + final int port = properties.getPort(); + if (port <= 0) { + throw new IllegalArgumentException("Port must be greater than 0"); + } else { + factory.setPort(port); + } + final boolean useNio = properties.isUseNio(); + if (useNio) { + factory.useNio(); + } + final boolean useSslProtocol = properties.isUseSslProtocol(); + if (useSslProtocol) { + try { + factory.useSslProtocol(); + } catch (NoSuchAlgorithmException | KeyManagementException e) { + throw new IllegalArgumentException("Invalid sslProtocol ", e); + } + } + factory.setConnectionTimeout(properties.getConnectionTimeoutInMilliSecs()); + factory.setRequestedHeartbeat(properties.getRequestHeartbeatTimeoutInSecs()); + factory.setNetworkRecoveryInterval(properties.getNetworkRecoveryIntervalInMilliSecs()); + factory.setHandshakeTimeout(properties.getHandshakeTimeoutInMilliSecs()); + factory.setAutomaticRecoveryEnabled(true); + factory.setTopologyRecoveryEnabled(true); + factory.setRequestedChannelMax(properties.getMaxChannelCount()); + return factory; + } + + public AMQPObservableQueue build(final boolean useExchange, final String queueURI) { + final AMQPSettings settings = new AMQPSettings(properties).fromURI(queueURI); + final AMQPRetryPattern retrySettings = + new AMQPRetryPattern( + properties.getLimit(), properties.getDuration(), properties.getType()); + return new AMQPObservableQueue( + factory, + addresses, + useExchange, + settings, + retrySettings, + batchSize, + pollTimeInMS); + } + } + + private AMQP.Exchange.DeclareOk getOrCreateExchange(ConnectionType connectionType) + throws Exception { + return getOrCreateExchange( + connectionType, + settings.getQueueOrExchangeName(), + settings.getExchangeType(), + settings.isDurable(), + settings.autoDelete(), + settings.getArguments()); + } + + private AMQP.Exchange.DeclareOk getOrCreateExchange( + ConnectionType connectionType, + String name, + final String type, + final boolean isDurable, + final boolean autoDelete, + final Map arguments) + throws Exception { + if (StringUtils.isEmpty(name)) { + throw new RuntimeException("Exchange name is undefined"); + } + if (StringUtils.isEmpty(type)) { + throw new RuntimeException("Exchange type is undefined"); + } + Channel chn = null; + try { + LOGGER.debug("Creating exchange {} of type {}", name, type); + chn = + amqpConnection.getOrCreateChannel( + connectionType, getSettings().getQueueOrExchangeName()); + return chn.exchangeDeclare(name, type, isDurable, autoDelete, arguments); + } catch (final Exception e) { + LOGGER.warn("Failed to create exchange {} of type {}", name, type, e); + throw e; + } finally { + if (chn != null) { + try { + amqpConnection.returnChannel(connectionType, chn); + } catch (Exception e) { + LOGGER.error("Failed to return the channel of {}. {}", connectionType, e); + } + } + } + } + + private AMQP.Queue.DeclareOk getOrCreateQueue(ConnectionType connectionType) throws Exception { + return getOrCreateQueue( + connectionType, + settings.getQueueOrExchangeName(), + settings.isDurable(), + settings.isExclusive(), + settings.autoDelete(), + settings.getArguments()); + } + + private AMQP.Queue.DeclareOk getOrCreateQueue( + ConnectionType connectionType, + final String name, + final boolean isDurable, + final boolean isExclusive, + final boolean autoDelete, + final Map arguments) + throws Exception { + if (StringUtils.isEmpty(name)) { + throw new RuntimeException("Queue name is undefined"); + } + arguments.put(QUEUE_TYPE, settings.getQueueType()); + Channel chn = null; + try { + LOGGER.debug("Creating queue {}", name); + chn = + amqpConnection.getOrCreateChannel( + connectionType, getSettings().getQueueOrExchangeName()); + return chn.queueDeclare(name, isDurable, isExclusive, autoDelete, arguments); + } catch (final Exception e) { + LOGGER.warn("Failed to create queue {}", name, e); + throw e; + } finally { + if (chn != null) { + try { + amqpConnection.returnChannel(connectionType, chn); + } catch (Exception e) { + LOGGER.error("Failed to return the channel of {}. {}", connectionType, e); + } + } + } + } + + private static Message asMessage(AMQPSettings settings, GetResponse response) throws Exception { + if (response == null) { + return null; + } + final Message message = new Message(); + message.setId(response.getProps().getMessageId()); + message.setPayload(new String(response.getBody(), settings.getContentEncoding())); + message.setReceipt(String.valueOf(response.getEnvelope().getDeliveryTag())); + return message; + } + + private void receiveMessagesFromQueue(String queueName) throws Exception { + LOGGER.debug("Accessing channel for queue {}", queueName); + + Consumer consumer = + new DefaultConsumer( + amqpConnection.getOrCreateChannel( + ConnectionType.SUBSCRIBER, + getSettings().getQueueOrExchangeName())) { + + @Override + public void handleDelivery( + final String consumerTag, + final Envelope envelope, + final AMQP.BasicProperties properties, + final byte[] body) + throws IOException { + try { + Message message = + asMessage( + settings, + new GetResponse( + envelope, properties, body, Integer.MAX_VALUE)); + if (message != null) { + if (LOGGER.isDebugEnabled()) { + LOGGER.debug( + "Got message with ID {} and receipt {}", + message.getId(), + message.getReceipt()); + } + messages.add(message); + LOGGER.info("receiveMessagesFromQueue- End method {}", messages); + } + } catch (InterruptedException e) { + LOGGER.error( + "Issue in handling the mesages for the subscriber with consumer tag {}. {}", + consumerTag, + e); + Thread.currentThread().interrupt(); + } catch (Exception e) { + LOGGER.error( + "Issue in handling the mesages for the subscriber with consumer tag {}. {}", + consumerTag, + e); + } + } + + public void handleCancel(String consumerTag) throws IOException { + LOGGER.error( + "Recieved a consumer cancel notification for subscriber {}", + consumerTag); + } + }; + + amqpConnection + .getOrCreateChannel( + ConnectionType.SUBSCRIBER, getSettings().getQueueOrExchangeName()) + .basicConsume(queueName, false, consumer); + Monitors.recordEventQueueMessagesProcessed(getType(), queueName, messages.size()); + } + + private void receiveMessagesFromQueue(String queueName, Subscriber subscriber) + throws Exception { + LOGGER.debug("Accessing channel for queue {}", queueName); + + Consumer consumer = + new DefaultConsumer( + amqpConnection.getOrCreateChannel( + ConnectionType.SUBSCRIBER, + getSettings().getQueueOrExchangeName())) { + + @Override + public void handleDelivery( + final String consumerTag, + final Envelope envelope, + final AMQP.BasicProperties properties, + final byte[] body) + throws IOException { + try { + Message message = + asMessage( + settings, + new GetResponse( + envelope, properties, body, Integer.MAX_VALUE)); + if (message == null) { + return; + } + LOGGER.info( + "Got message with ID {} and receipt {}", + message.getId(), + message.getReceipt()); + LOGGER.debug("Message content {}", message); + // Not using thread-pool here as the number of concurrent threads are + // controlled + // by the number of messages delivery using pre-fetch count in RabbitMQ + Thread newThread = + new Thread( + () -> { + LOGGER.info( + "Spawning a new thread for message with ID {}", + message.getId()); + subscriber.onNext(message); + }); + newThread.start(); + } catch (InterruptedException e) { + LOGGER.error( + "Issue in handling the mesages for the subscriber with consumer tag {}. {}", + consumerTag, + e); + Thread.currentThread().interrupt(); + } catch (Exception e) { + LOGGER.error( + "Issue in handling the mesages for the subscriber with consumer tag {}. {}", + consumerTag, + e); + } + } + + public void handleCancel(String consumerTag) throws IOException { + LOGGER.error( + "Recieved a consumer cancel notification for subscriber {}", + consumerTag); + } + }; + amqpConnection + .getOrCreateChannel( + ConnectionType.SUBSCRIBER, getSettings().getQueueOrExchangeName()) + .basicConsume(queueName, false, consumer); + } + + protected void receiveMessages() { + try { + amqpConnection + .getOrCreateChannel( + ConnectionType.SUBSCRIBER, getSettings().getQueueOrExchangeName()) + .basicQos(batchSize); + String queueName; + if (useExchange) { + // Consume messages from an exchange + getOrCreateExchange(ConnectionType.SUBSCRIBER); + /* + * Create queue if not present based on the settings provided in the queue URI + * or configuration properties. Sample URI format: + * amqp_exchange:myExchange?bindQueueName=myQueue&exchangeType=topic&routingKey=myRoutingKey&exclusive + * =false&autoDelete=false&durable=true Default settings if not provided in the + * queue URI or properties: isDurable: true, autoDelete: false, isExclusive: + * false The same settings are currently used during creation of exchange as + * well as queue. TODO: This can be enhanced further to get the settings + * separately for exchange and queue from the URI + */ + final AMQP.Queue.DeclareOk declareOk = + getOrCreateQueue( + ConnectionType.SUBSCRIBER, + settings.getExchangeBoundQueueName(), + settings.isDurable(), + settings.isExclusive(), + settings.autoDelete(), + Maps.newHashMap()); + // Bind the declared queue to exchange + queueName = declareOk.getQueue(); + amqpConnection + .getOrCreateChannel( + ConnectionType.SUBSCRIBER, getSettings().getQueueOrExchangeName()) + .queueBind( + queueName, + settings.getQueueOrExchangeName(), + settings.getRoutingKey()); + } else { + // Consume messages from a queue + queueName = getOrCreateQueue(ConnectionType.SUBSCRIBER).getQueue(); + } + // Consume messages + LOGGER.info("Consuming from queue {}", queueName); + receiveMessagesFromQueue(queueName); + } catch (Exception exception) { + LOGGER.error("Exception while getting messages from RabbitMQ", exception); + Monitors.recordObservableQMessageReceivedErrors(getType()); + } + } + + protected void receiveMessages(Subscriber subscriber) { + try { + amqpConnection + .getOrCreateChannel( + ConnectionType.SUBSCRIBER, getSettings().getQueueOrExchangeName()) + .basicQos(batchSize); + String queueName; + if (useExchange) { + // Consume messages from an exchange + getOrCreateExchange(ConnectionType.SUBSCRIBER); + /* + * Create queue if not present based on the settings provided in the queue URI + * or configuration properties. Sample URI format: + * amqp_exchange:myExchange?bindQueueName=myQueue&exchangeType=topic&routingKey=myRoutingKey&exclusive + * =false&autoDelete=false&durable=true Default settings if not provided in the + * queue URI or properties: isDurable: true, autoDelete: false, isExclusive: + * false The same settings are currently used during creation of exchange as + * well as queue. TODO: This can be enhanced further to get the settings + * separately for exchange and queue from the URI + */ + final AMQP.Queue.DeclareOk declareOk = + getOrCreateQueue( + ConnectionType.SUBSCRIBER, + settings.getExchangeBoundQueueName(), + settings.isDurable(), + settings.isExclusive(), + settings.autoDelete(), + Maps.newHashMap()); + // Bind the declared queue to exchange + queueName = declareOk.getQueue(); + amqpConnection + .getOrCreateChannel( + ConnectionType.SUBSCRIBER, settings.getQueueOrExchangeName()) + .queueBind( + queueName, + settings.getQueueOrExchangeName(), + settings.getRoutingKey()); + } else { + // Consume messages from a queue + queueName = getOrCreateQueue(ConnectionType.SUBSCRIBER).getQueue(); + } + // Consume messages + LOGGER.info("Consuming from queue {}", queueName); + receiveMessagesFromQueue(queueName, subscriber); + } catch (Exception exception) { + LOGGER.error("Exception while getting messages from RabbitMQ", exception); + Monitors.recordObservableQMessageReceivedErrors(getType()); + } + } + + public int getPollTimeInMS() { + return pollTimeInMS; + } + + public void setPollTimeInMS(int pollTimeInMS) { + this.pollTimeInMS = pollTimeInMS; + } +} diff --git a/amqp/src/main/java/com/netflix/conductor/contribs/queue/amqp/config/AMQPEventQueueConfiguration.java b/amqp/src/main/java/com/netflix/conductor/contribs/queue/amqp/config/AMQPEventQueueConfiguration.java new file mode 100644 index 000000000..a4e23d232 --- /dev/null +++ b/amqp/src/main/java/com/netflix/conductor/contribs/queue/amqp/config/AMQPEventQueueConfiguration.java @@ -0,0 +1,86 @@ +/* + * Copyright 2023 Conductor Authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package com.netflix.conductor.contribs.queue.amqp.config; + +import java.util.HashMap; +import java.util.Map; + +import org.apache.commons.lang3.StringUtils; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import com.netflix.conductor.contribs.queue.amqp.AMQPObservableQueue.Builder; +import com.netflix.conductor.core.config.ConductorProperties; +import com.netflix.conductor.core.events.EventQueueProvider; +import com.netflix.conductor.core.events.queue.ObservableQueue; +import com.netflix.conductor.model.TaskModel.Status; + +@Configuration(proxyBeanMethods = false) +@EnableConfigurationProperties(AMQPEventQueueProperties.class) +@ConditionalOnProperty(name = "conductor.event-queues.amqp.enabled", havingValue = "true") +public class AMQPEventQueueConfiguration { + + private enum QUEUE_TYPE { + AMQP_QUEUE("amqp_queue"), + AMQP_EXCHANGE("amqp_exchange"); + + private final String type; + + QUEUE_TYPE(String type) { + this.type = type; + } + + public String getType() { + return type; + } + } + + @Bean + public EventQueueProvider amqpEventQueueProvider(AMQPEventQueueProperties properties) { + return new AMQPEventQueueProvider(properties, QUEUE_TYPE.AMQP_QUEUE.getType(), false); + } + + @Bean + public EventQueueProvider amqpExchangeEventQueueProvider(AMQPEventQueueProperties properties) { + return new AMQPEventQueueProvider(properties, QUEUE_TYPE.AMQP_EXCHANGE.getType(), true); + } + + @ConditionalOnProperty(name = "conductor.default-event-queue.type", havingValue = "amqp") + @Bean + public Map getQueues( + ConductorProperties conductorProperties, AMQPEventQueueProperties properties) { + String stack = ""; + if (conductorProperties.getStack() != null && conductorProperties.getStack().length() > 0) { + stack = conductorProperties.getStack() + "_"; + } + final boolean useExchange = properties.isUseExchange(); + + Status[] statuses = new Status[] {Status.COMPLETED, Status.FAILED}; + Map queues = new HashMap<>(); + for (Status status : statuses) { + String queuePrefix = + StringUtils.isBlank(properties.getListenerQueuePrefix()) + ? conductorProperties.getAppId() + "_amqp_notify_" + stack + : properties.getListenerQueuePrefix(); + + String queueName = queuePrefix + status.name(); + + final ObservableQueue queue = new Builder(properties).build(useExchange, queueName); + queues.put(status, queue); + } + + return queues; + } +} diff --git a/amqp/src/main/java/com/netflix/conductor/contribs/queue/amqp/config/AMQPEventQueueProperties.java b/amqp/src/main/java/com/netflix/conductor/contribs/queue/amqp/config/AMQPEventQueueProperties.java new file mode 100644 index 000000000..bbf3aab9c --- /dev/null +++ b/amqp/src/main/java/com/netflix/conductor/contribs/queue/amqp/config/AMQPEventQueueProperties.java @@ -0,0 +1,313 @@ +/* + * Copyright 2023 Conductor Authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package com.netflix.conductor.contribs.queue.amqp.config; + +import java.time.Duration; + +import org.springframework.boot.context.properties.ConfigurationProperties; + +import com.netflix.conductor.contribs.queue.amqp.util.RetryType; + +import com.rabbitmq.client.AMQP.PROTOCOL; +import com.rabbitmq.client.ConnectionFactory; + +@ConfigurationProperties("conductor.event-queues.amqp") +public class AMQPEventQueueProperties { + + private int batchSize = 1; + + private Duration pollTimeDuration = Duration.ofMillis(100); + + private String hosts = ConnectionFactory.DEFAULT_HOST; + + private String username = ConnectionFactory.DEFAULT_USER; + + private String password = ConnectionFactory.DEFAULT_PASS; + + private String virtualHost = ConnectionFactory.DEFAULT_VHOST; + + private int port = PROTOCOL.PORT; + + private int connectionTimeoutInMilliSecs = 180000; + private int networkRecoveryIntervalInMilliSecs = 5000; + private int requestHeartbeatTimeoutInSecs = 30; + private int handshakeTimeoutInMilliSecs = 180000; + private int maxChannelCount = 5000; + private int limit = 50; + private int duration = 1000; + private RetryType retryType = RetryType.REGULARINTERVALS; + + public int getLimit() { + return limit; + } + + public void setLimit(int limit) { + this.limit = limit; + } + + public int getDuration() { + return duration; + } + + public void setDuration(int duration) { + this.duration = duration; + } + + public RetryType getType() { + return retryType; + } + + public void setType(RetryType type) { + this.retryType = type; + } + + public int getConnectionTimeoutInMilliSecs() { + return connectionTimeoutInMilliSecs; + } + + public void setConnectionTimeoutInMilliSecs(int connectionTimeoutInMilliSecs) { + this.connectionTimeoutInMilliSecs = connectionTimeoutInMilliSecs; + } + + public int getHandshakeTimeoutInMilliSecs() { + return handshakeTimeoutInMilliSecs; + } + + public void setHandshakeTimeoutInMilliSecs(int handshakeTimeoutInMilliSecs) { + this.handshakeTimeoutInMilliSecs = handshakeTimeoutInMilliSecs; + } + + public int getMaxChannelCount() { + return maxChannelCount; + } + + public void setMaxChannelCount(int maxChannelCount) { + this.maxChannelCount = maxChannelCount; + } + + private boolean useNio = false; + + private boolean durable = true; + + private boolean exclusive = false; + + private boolean autoDelete = false; + + private String contentType = "application/json"; + + private String contentEncoding = "UTF-8"; + + private String exchangeType = "topic"; + + private String queueType = "classic"; + + private boolean sequentialMsgProcessing = true; + + private int deliveryMode = 2; + + private boolean useExchange = true; + + private String listenerQueuePrefix = ""; + + private boolean useSslProtocol = false; + + public int getBatchSize() { + return batchSize; + } + + public void setBatchSize(int batchSize) { + this.batchSize = batchSize; + } + + public Duration getPollTimeDuration() { + return pollTimeDuration; + } + + public void setPollTimeDuration(Duration pollTimeDuration) { + this.pollTimeDuration = pollTimeDuration; + } + + public String getHosts() { + return hosts; + } + + public void setHosts(String hosts) { + this.hosts = hosts; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + public String getVirtualHost() { + return virtualHost; + } + + public void setVirtualHost(String virtualHost) { + this.virtualHost = virtualHost; + } + + public int getPort() { + return port; + } + + public void setPort(int port) { + this.port = port; + } + + public boolean isUseNio() { + return useNio; + } + + public void setUseNio(boolean useNio) { + this.useNio = useNio; + } + + public boolean isDurable() { + return durable; + } + + public void setDurable(boolean durable) { + this.durable = durable; + } + + public boolean isExclusive() { + return exclusive; + } + + public void setExclusive(boolean exclusive) { + this.exclusive = exclusive; + } + + public boolean isAutoDelete() { + return autoDelete; + } + + public void setAutoDelete(boolean autoDelete) { + this.autoDelete = autoDelete; + } + + public String getContentType() { + return contentType; + } + + public void setContentType(String contentType) { + this.contentType = contentType; + } + + public String getContentEncoding() { + return contentEncoding; + } + + public void setContentEncoding(String contentEncoding) { + this.contentEncoding = contentEncoding; + } + + public String getExchangeType() { + return exchangeType; + } + + public void setExchangeType(String exchangeType) { + this.exchangeType = exchangeType; + } + + public int getDeliveryMode() { + return deliveryMode; + } + + public void setDeliveryMode(int deliveryMode) { + this.deliveryMode = deliveryMode; + } + + public boolean isUseExchange() { + return useExchange; + } + + public void setUseExchange(boolean useExchange) { + this.useExchange = useExchange; + } + + public String getListenerQueuePrefix() { + return listenerQueuePrefix; + } + + public void setListenerQueuePrefix(String listenerQueuePrefix) { + this.listenerQueuePrefix = listenerQueuePrefix; + } + + public String getQueueType() { + return queueType; + } + + public boolean isUseSslProtocol() { + return useSslProtocol; + } + + public void setUseSslProtocol(boolean useSslProtocol) { + this.useSslProtocol = useSslProtocol; + } + + /** + * @param queueType Supports two queue types, 'classic' and 'quorum'. Classic will be be + * deprecated in 2022 and its usage discouraged from RabbitMQ community. So not using enum + * type here to hold different values. + */ + public void setQueueType(String queueType) { + this.queueType = queueType; + } + + /** + * @return the sequentialMsgProcessing + */ + public boolean isSequentialMsgProcessing() { + return sequentialMsgProcessing; + } + + /** + * @param sequentialMsgProcessing the sequentialMsgProcessing to set Supports sequential and + * parallel message processing capabilities. In parallel message processing, number of + * threads are controlled by batch size. No thread control or execution framework required + * here as threads are limited and short-lived. + */ + public void setSequentialMsgProcessing(boolean sequentialMsgProcessing) { + this.sequentialMsgProcessing = sequentialMsgProcessing; + } + + public int getNetworkRecoveryIntervalInMilliSecs() { + return networkRecoveryIntervalInMilliSecs; + } + + public void setNetworkRecoveryIntervalInMilliSecs(int networkRecoveryIntervalInMilliSecs) { + this.networkRecoveryIntervalInMilliSecs = networkRecoveryIntervalInMilliSecs; + } + + public int getRequestHeartbeatTimeoutInSecs() { + return requestHeartbeatTimeoutInSecs; + } + + public void setRequestHeartbeatTimeoutInSecs(int requestHeartbeatTimeoutInSecs) { + this.requestHeartbeatTimeoutInSecs = requestHeartbeatTimeoutInSecs; + } +} diff --git a/amqp/src/main/java/com/netflix/conductor/contribs/queue/amqp/config/AMQPEventQueueProvider.java b/amqp/src/main/java/com/netflix/conductor/contribs/queue/amqp/config/AMQPEventQueueProvider.java new file mode 100644 index 000000000..6e17ef8ef --- /dev/null +++ b/amqp/src/main/java/com/netflix/conductor/contribs/queue/amqp/config/AMQPEventQueueProvider.java @@ -0,0 +1,59 @@ +/* + * Copyright 2023 Conductor Authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package com.netflix.conductor.contribs.queue.amqp.config; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.lang.NonNull; + +import com.netflix.conductor.contribs.queue.amqp.AMQPObservableQueue; +import com.netflix.conductor.contribs.queue.amqp.AMQPObservableQueue.Builder; +import com.netflix.conductor.core.events.EventQueueProvider; +import com.netflix.conductor.core.events.queue.ObservableQueue; + +/** + * @author Ritu Parathody + */ +public class AMQPEventQueueProvider implements EventQueueProvider { + + private static final Logger LOGGER = LoggerFactory.getLogger(AMQPEventQueueProvider.class); + protected Map queues = new ConcurrentHashMap<>(); + private final boolean useExchange; + private final AMQPEventQueueProperties properties; + private final String queueType; + + public AMQPEventQueueProvider( + AMQPEventQueueProperties properties, String queueType, boolean useExchange) { + this.properties = properties; + this.queueType = queueType; + this.useExchange = useExchange; + } + + @Override + public String getQueueType() { + return queueType; + } + + @Override + @NonNull + public ObservableQueue getQueue(String queueURI) { + if (LOGGER.isInfoEnabled()) { + LOGGER.info("Retrieve queue with URI {}", queueURI); + } + // Build the queue with the inner Builder class of AMQPObservableQueue + return queues.computeIfAbsent(queueURI, q -> new Builder(properties).build(useExchange, q)); + } +} diff --git a/amqp/src/main/java/com/netflix/conductor/contribs/queue/amqp/config/AMQPRetryPattern.java b/amqp/src/main/java/com/netflix/conductor/contribs/queue/amqp/config/AMQPRetryPattern.java new file mode 100644 index 000000000..6d9d159a5 --- /dev/null +++ b/amqp/src/main/java/com/netflix/conductor/contribs/queue/amqp/config/AMQPRetryPattern.java @@ -0,0 +1,54 @@ +/* + * Copyright 2023 Conductor Authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package com.netflix.conductor.contribs.queue.amqp.config; + +import com.netflix.conductor.contribs.queue.amqp.util.RetryType; + +public class AMQPRetryPattern { + + private int limit = 50; + private int duration = 1000; + private RetryType type = RetryType.REGULARINTERVALS; + + public AMQPRetryPattern() {} + + public AMQPRetryPattern(int limit, int duration, RetryType type) { + this.limit = limit; + this.duration = duration; + this.type = type; + } + + /** + * This gets executed if the retry index is within the allowed limits, otherwise exception will + * be thrown. + * + * @throws Exception + */ + public void continueOrPropogate(Exception ex, int retryIndex) throws Exception { + if (retryIndex > limit) { + throw ex; + } + // Regular Intervals is the default + long waitDuration = duration; + if (type == RetryType.INCREMENTALINTERVALS) { + waitDuration = duration * retryIndex; + } else if (type == RetryType.EXPONENTIALBACKOFF) { + waitDuration = (long) Math.pow(2, retryIndex) * duration; + } + try { + Thread.sleep(waitDuration); + } catch (InterruptedException ignored) { + Thread.currentThread().interrupt(); + } + } +} diff --git a/amqp/src/main/java/com/netflix/conductor/contribs/queue/amqp/util/AMQPConfigurations.java b/amqp/src/main/java/com/netflix/conductor/contribs/queue/amqp/util/AMQPConfigurations.java new file mode 100644 index 000000000..d0d3b93c5 --- /dev/null +++ b/amqp/src/main/java/com/netflix/conductor/contribs/queue/amqp/util/AMQPConfigurations.java @@ -0,0 +1,40 @@ +/* + * Copyright 2023 Conductor Authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package com.netflix.conductor.contribs.queue.amqp.util; + +/** + * @author Ritu Parathody + */ +public enum AMQPConfigurations { + + // queue exchange settings + PARAM_EXCHANGE_TYPE("exchangeType"), + PARAM_QUEUE_NAME("bindQueueName"), + PARAM_ROUTING_KEY("routingKey"), + PARAM_DELIVERY_MODE("deliveryMode"), + PARAM_DURABLE("durable"), + PARAM_EXCLUSIVE("exclusive"), + PARAM_AUTO_DELETE("autoDelete"), + PARAM_MAX_PRIORITY("maxPriority"); + + String propertyName; + + AMQPConfigurations(String propertyName) { + this.propertyName = propertyName; + } + + @Override + public String toString() { + return propertyName; + } +} diff --git a/amqp/src/main/java/com/netflix/conductor/contribs/queue/amqp/util/AMQPConstants.java b/amqp/src/main/java/com/netflix/conductor/contribs/queue/amqp/util/AMQPConstants.java new file mode 100644 index 000000000..3abd619bf --- /dev/null +++ b/amqp/src/main/java/com/netflix/conductor/contribs/queue/amqp/util/AMQPConstants.java @@ -0,0 +1,91 @@ +/* + * Copyright 2023 Conductor Authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package com.netflix.conductor.contribs.queue.amqp.util; + +/** + * @author Ritu Parathody + */ +public class AMQPConstants { + + /** this when set will create a rabbitmq queue */ + public static String AMQP_QUEUE_TYPE = "amqp_queue"; + + /** this when set will create a rabbitmq exchange */ + public static String AMQP_EXCHANGE_TYPE = "amqp_exchange"; + + public static String PROPERTY_KEY_TEMPLATE = "conductor.event-queues.amqp.%s"; + + /** default content type for the message read from rabbitmq */ + public static String DEFAULT_CONTENT_TYPE = "application/json"; + + /** default encoding for the message read from rabbitmq */ + public static String DEFAULT_CONTENT_ENCODING = "UTF-8"; + + /** default rabbitmq exchange type */ + public static String DEFAULT_EXCHANGE_TYPE = "topic"; + + /** + * default rabbitmq durability When set to true the queues are persisted to the disk. + * + *

{@see RabbitMQ}. + */ + public static boolean DEFAULT_DURABLE = true; + + /** + * default rabbitmq exclusivity When set to true the queues can be only used by one connection. + * + *

{@see RabbitMQ}. + */ + public static boolean DEFAULT_EXCLUSIVE = false; + + /** + * default rabbitmq auto delete When set to true the queues will be deleted when the last + * consumer is cancelled + * + *

{@see RabbitMQ}. + */ + public static boolean DEFAULT_AUTO_DELETE = false; + + /** + * default rabbitmq delivery mode This is a property of the message When set to 1 the will be + * non persistent and 2 will be persistent {@see Consumer Prefetch}. + */ + public static int DEFAULT_BATCH_SIZE = 1; + + /** + * default rabbitmq delivery mode This is a property of the amqp implementation which sets teh + * polling time to drain the in-memory queue. + */ + public static int DEFAULT_POLL_TIME_MS = 100; + + // info channel messages. + public static final String INFO_CHANNEL_BORROW_SUCCESS = + "Borrowed the channel object from the channel pool for " + "the connection type [%s]"; + public static final String INFO_CHANNEL_RETURN_SUCCESS = + "Returned the borrowed channel object to the pool for " + "the connection type [%s]"; + public static final String INFO_CHANNEL_CREATION_SUCCESS = + "Channels are not available in the pool. Created a" + + " channel for the connection type [%s]"; + public static final String INFO_CHANNEL_RESET_SUCCESS = + "No proper channels available in the pool. Created a " + + "channel for the connection type [%s]"; +} diff --git a/amqp/src/main/java/com/netflix/conductor/contribs/queue/amqp/util/AMQPSettings.java b/amqp/src/main/java/com/netflix/conductor/contribs/queue/amqp/util/AMQPSettings.java new file mode 100644 index 000000000..db18dd9df --- /dev/null +++ b/amqp/src/main/java/com/netflix/conductor/contribs/queue/amqp/util/AMQPSettings.java @@ -0,0 +1,315 @@ +/* + * Copyright 2023 Conductor Authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package com.netflix.conductor.contribs.queue.amqp.util; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.netflix.conductor.contribs.queue.amqp.config.AMQPEventQueueProperties; + +import static com.netflix.conductor.contribs.queue.amqp.util.AMQPConfigurations.*; + +/** + * @author Ritu Parathody + */ +public class AMQPSettings { + + private static final Pattern URI_PATTERN = + Pattern.compile( + "^(?:amqp\\_(queue|exchange))?\\:?(?[^\\?]+)\\??(?.*)$", + Pattern.CASE_INSENSITIVE); + + private String queueOrExchangeName; + private String eventName; + private String exchangeType; + private String exchangeBoundQueueName; + private String queueType; + private String routingKey; + private final String contentEncoding; + private final String contentType; + private boolean durable; + private boolean exclusive; + private boolean autoDelete; + private boolean sequentialProcessing; + private int deliveryMode; + + private final Map arguments = new HashMap<>(); + private static final Logger LOGGER = LoggerFactory.getLogger(AMQPSettings.class); + + public AMQPSettings(final AMQPEventQueueProperties properties) { + // Initialize with a default values + durable = properties.isDurable(); + exclusive = properties.isExclusive(); + autoDelete = properties.isAutoDelete(); + contentType = properties.getContentType(); + contentEncoding = properties.getContentEncoding(); + exchangeType = properties.getExchangeType(); + routingKey = StringUtils.EMPTY; + queueType = properties.getQueueType(); + sequentialProcessing = properties.isSequentialMsgProcessing(); + // Set common settings for publishing and consuming + setDeliveryMode(properties.getDeliveryMode()); + } + + public final boolean isDurable() { + return durable; + } + + public final boolean isExclusive() { + return exclusive; + } + + public final boolean autoDelete() { + return autoDelete; + } + + public final Map getArguments() { + return arguments; + } + + public final String getContentEncoding() { + return contentEncoding; + } + + /** + * Use queue for publishing + * + * @param queueName the name of queue + */ + public void setQueue(String queueName) { + if (StringUtils.isEmpty(queueName)) { + throw new IllegalArgumentException("Queue name for publishing is undefined"); + } + this.queueOrExchangeName = queueName; + } + + public String getQueueOrExchangeName() { + return queueOrExchangeName; + } + + public String getExchangeBoundQueueName() { + if (StringUtils.isEmpty(exchangeBoundQueueName)) { + return String.format("bound_to_%s", queueOrExchangeName); + } + return exchangeBoundQueueName; + } + + public String getExchangeType() { + return exchangeType; + } + + public String getRoutingKey() { + return routingKey; + } + + public int getDeliveryMode() { + return deliveryMode; + } + + public AMQPSettings setDeliveryMode(int deliveryMode) { + if (deliveryMode != 1 && deliveryMode != 2) { + throw new IllegalArgumentException("Delivery mode must be 1 or 2"); + } + this.deliveryMode = deliveryMode; + return this; + } + + public String getContentType() { + return contentType; + } + + /** + * Complete settings from the queue URI. + * + *

Example for queue: + * + *

+     * amqp_queue:myQueue?deliveryMode=1&autoDelete=true&exclusive=true
+     * 
+ * + * Example for exchange: + * + *
+     * amqp_exchange:myExchange?bindQueueName=myQueue&exchangeType=topic&routingKey=myRoutingKey&exclusive=true
+     * 
+ * + * @param queueURI + * @return + */ + public final AMQPSettings fromURI(final String queueURI) { + final Matcher matcher = URI_PATTERN.matcher(queueURI); + if (!matcher.matches()) { + throw new IllegalArgumentException("Queue URI doesn't matches the expected regexp"); + } + + // Set name of queue or exchange from group "name" + LOGGER.info("Queue URI:{}", queueURI); + queueOrExchangeName = matcher.group("name"); + eventName = queueURI; + if (matcher.groupCount() > 1) { + final String queryParams = matcher.group("params"); + if (StringUtils.isNotEmpty(queryParams)) { + // Handle parameters + Arrays.stream(queryParams.split("\\s*\\&\\s*")) + .forEach( + param -> { + final String[] kv = param.split("\\s*=\\s*"); + if (kv.length == 2) { + if (kv[0].equalsIgnoreCase( + String.valueOf(PARAM_EXCHANGE_TYPE))) { + String value = kv[1]; + if (StringUtils.isEmpty(value)) { + throw new IllegalArgumentException( + "The provided exchange type is empty"); + } + exchangeType = value; + } + if (kv[0].equalsIgnoreCase( + (String.valueOf(PARAM_QUEUE_NAME)))) { + exchangeBoundQueueName = kv[1]; + } + if (kv[0].equalsIgnoreCase( + (String.valueOf(PARAM_ROUTING_KEY)))) { + String value = kv[1]; + if (StringUtils.isEmpty(value)) { + throw new IllegalArgumentException( + "The provided routing key is empty"); + } + routingKey = value; + } + if (kv[0].equalsIgnoreCase( + (String.valueOf(PARAM_DURABLE)))) { + durable = Boolean.parseBoolean(kv[1]); + } + if (kv[0].equalsIgnoreCase( + (String.valueOf(PARAM_EXCLUSIVE)))) { + exclusive = Boolean.parseBoolean(kv[1]); + } + if (kv[0].equalsIgnoreCase( + (String.valueOf(PARAM_AUTO_DELETE)))) { + autoDelete = Boolean.parseBoolean(kv[1]); + } + if (kv[0].equalsIgnoreCase( + (String.valueOf(PARAM_DELIVERY_MODE)))) { + setDeliveryMode(Integer.parseInt(kv[1])); + } + if (kv[0].equalsIgnoreCase( + (String.valueOf(PARAM_MAX_PRIORITY)))) { + arguments.put("x-max-priority", Integer.valueOf(kv[1])); + } + } + }); + } + } + return this; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (!(obj instanceof AMQPSettings)) return false; + AMQPSettings other = (AMQPSettings) obj; + return Objects.equals(arguments, other.arguments) + && autoDelete == other.autoDelete + && Objects.equals(contentEncoding, other.contentEncoding) + && Objects.equals(contentType, other.contentType) + && deliveryMode == other.deliveryMode + && durable == other.durable + && Objects.equals(eventName, other.eventName) + && Objects.equals(exchangeType, other.exchangeType) + && exclusive == other.exclusive + && Objects.equals(queueOrExchangeName, other.queueOrExchangeName) + && Objects.equals(exchangeBoundQueueName, other.exchangeBoundQueueName) + && Objects.equals(queueType, other.queueType) + && Objects.equals(routingKey, other.routingKey) + && sequentialProcessing == other.sequentialProcessing; + } + + @Override + public int hashCode() { + return Objects.hash( + arguments, + autoDelete, + contentEncoding, + contentType, + deliveryMode, + durable, + eventName, + exchangeType, + exclusive, + queueOrExchangeName, + exchangeBoundQueueName, + queueType, + routingKey, + sequentialProcessing); + } + + @Override + public String toString() { + return "AMQPSettings [queueOrExchangeName=" + + queueOrExchangeName + + ", eventName=" + + eventName + + ", exchangeType=" + + exchangeType + + ", exchangeQueueName=" + + exchangeBoundQueueName + + ", queueType=" + + queueType + + ", routingKey=" + + routingKey + + ", contentEncoding=" + + contentEncoding + + ", contentType=" + + contentType + + ", durable=" + + durable + + ", exclusive=" + + exclusive + + ", autoDelete=" + + autoDelete + + ", sequentialProcessing=" + + sequentialProcessing + + ", deliveryMode=" + + deliveryMode + + ", arguments=" + + arguments + + "]"; + } + + public String getEventName() { + return eventName; + } + + /** + * @return the queueType + */ + public String getQueueType() { + return queueType; + } + + /** + * @return the sequentialProcessing + */ + public boolean isSequentialProcessing() { + return sequentialProcessing; + } +} diff --git a/amqp/src/main/java/com/netflix/conductor/contribs/queue/amqp/util/ConnectionType.java b/amqp/src/main/java/com/netflix/conductor/contribs/queue/amqp/util/ConnectionType.java new file mode 100644 index 000000000..0b28ce273 --- /dev/null +++ b/amqp/src/main/java/com/netflix/conductor/contribs/queue/amqp/util/ConnectionType.java @@ -0,0 +1,18 @@ +/* + * Copyright 2023 Conductor Authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package com.netflix.conductor.contribs.queue.amqp.util; + +public enum ConnectionType { + PUBLISHER, + SUBSCRIBER +} diff --git a/amqp/src/main/java/com/netflix/conductor/contribs/queue/amqp/util/RetryType.java b/amqp/src/main/java/com/netflix/conductor/contribs/queue/amqp/util/RetryType.java new file mode 100644 index 000000000..192c49f25 --- /dev/null +++ b/amqp/src/main/java/com/netflix/conductor/contribs/queue/amqp/util/RetryType.java @@ -0,0 +1,20 @@ +/* + * Copyright 2023 Conductor Authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package com.netflix.conductor.contribs.queue.amqp.util; + +/** RetryType holds the retry type */ +public enum RetryType { + REGULARINTERVALS, + EXPONENTIALBACKOFF, + INCREMENTALINTERVALS +} diff --git a/amqp/src/test/java/com/netflix/conductor/contribs/queue/amqp/AMQPEventQueueProviderTest.java b/amqp/src/test/java/com/netflix/conductor/contribs/queue/amqp/AMQPEventQueueProviderTest.java new file mode 100644 index 000000000..2ca8a781a --- /dev/null +++ b/amqp/src/test/java/com/netflix/conductor/contribs/queue/amqp/AMQPEventQueueProviderTest.java @@ -0,0 +1,82 @@ +/* + * Copyright 2023 Conductor Authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package com.netflix.conductor.contribs.queue.amqp; + +import java.time.Duration; + +import org.junit.Before; +import org.junit.Test; + +import com.netflix.conductor.contribs.queue.amqp.config.AMQPEventQueueProperties; +import com.netflix.conductor.contribs.queue.amqp.config.AMQPEventQueueProvider; +import com.netflix.conductor.contribs.queue.amqp.util.AMQPConstants; +import com.netflix.conductor.core.events.queue.ObservableQueue; + +import com.rabbitmq.client.AMQP.PROTOCOL; +import com.rabbitmq.client.ConnectionFactory; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class AMQPEventQueueProviderTest { + + private AMQPEventQueueProperties properties; + + @Before + public void setUp() { + properties = mock(AMQPEventQueueProperties.class); + when(properties.getBatchSize()).thenReturn(1); + when(properties.getPollTimeDuration()).thenReturn(Duration.ofMillis(100)); + when(properties.getHosts()).thenReturn(ConnectionFactory.DEFAULT_HOST); + when(properties.getUsername()).thenReturn(ConnectionFactory.DEFAULT_USER); + when(properties.getPassword()).thenReturn(ConnectionFactory.DEFAULT_PASS); + when(properties.getVirtualHost()).thenReturn(ConnectionFactory.DEFAULT_VHOST); + when(properties.getPort()).thenReturn(PROTOCOL.PORT); + when(properties.getConnectionTimeoutInMilliSecs()).thenReturn(60000); + when(properties.isUseNio()).thenReturn(false); + when(properties.isDurable()).thenReturn(true); + when(properties.isExclusive()).thenReturn(false); + when(properties.isAutoDelete()).thenReturn(false); + when(properties.getContentType()).thenReturn("application/json"); + when(properties.getContentEncoding()).thenReturn("UTF-8"); + when(properties.getExchangeType()).thenReturn("topic"); + when(properties.getDeliveryMode()).thenReturn(2); + when(properties.isUseExchange()).thenReturn(true); + } + + @Test + public void testAMQPEventQueueProvider_defaultconfig_exchange() { + String exchangestring = + "amqp_exchange:myExchangeName?exchangeType=topic&routingKey=test&deliveryMode=2"; + AMQPEventQueueProvider eventqProvider = + new AMQPEventQueueProvider(properties, "amqp_exchange", true); + ObservableQueue queue = eventqProvider.getQueue(exchangestring); + assertNotNull(queue); + assertEquals(exchangestring, queue.getName()); + assertEquals(AMQPConstants.AMQP_EXCHANGE_TYPE, queue.getType()); + } + + @Test + public void testAMQPEventQueueProvider_defaultconfig_queue() { + String exchangestring = + "amqp_queue:myQueueName?deliveryMode=2&durable=false&autoDelete=true&exclusive=true"; + AMQPEventQueueProvider eventqProvider = + new AMQPEventQueueProvider(properties, "amqp_queue", false); + ObservableQueue queue = eventqProvider.getQueue(exchangestring); + assertNotNull(queue); + assertEquals(exchangestring, queue.getName()); + assertEquals(AMQPConstants.AMQP_QUEUE_TYPE, queue.getType()); + } +} diff --git a/amqp/src/test/java/com/netflix/conductor/contribs/queue/amqp/AMQPObservableQueueTest.java b/amqp/src/test/java/com/netflix/conductor/contribs/queue/amqp/AMQPObservableQueueTest.java new file mode 100644 index 000000000..1b6139a4a --- /dev/null +++ b/amqp/src/test/java/com/netflix/conductor/contribs/queue/amqp/AMQPObservableQueueTest.java @@ -0,0 +1,911 @@ +/* + * Copyright 2023 Conductor Authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package com.netflix.conductor.contribs.queue.amqp; + +import java.io.IOException; +import java.time.Duration; +import java.util.ArrayList; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import java.util.Random; +import java.util.UUID; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +import org.apache.commons.lang3.RandomStringUtils; +import org.apache.commons.lang3.StringUtils; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mockito; +import org.mockito.internal.stubbing.answers.DoesNothing; +import org.mockito.stubbing.OngoingStubbing; + +import com.netflix.conductor.contribs.queue.amqp.config.AMQPEventQueueProperties; +import com.netflix.conductor.contribs.queue.amqp.config.AMQPRetryPattern; +import com.netflix.conductor.contribs.queue.amqp.util.AMQPConstants; +import com.netflix.conductor.contribs.queue.amqp.util.AMQPSettings; +import com.netflix.conductor.contribs.queue.amqp.util.RetryType; +import com.netflix.conductor.core.events.queue.Message; + +import com.rabbitmq.client.AMQP; +import com.rabbitmq.client.AMQP.PROTOCOL; +import com.rabbitmq.client.AMQP.Queue.DeclareOk; +import com.rabbitmq.client.Address; +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.Connection; +import com.rabbitmq.client.ConnectionFactory; +import com.rabbitmq.client.Consumer; +import com.rabbitmq.client.Envelope; +import com.rabbitmq.client.GetResponse; +import com.rabbitmq.client.impl.AMQImpl; +import rx.Observable; +import rx.observers.Subscribers; +import rx.observers.TestSubscriber; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.anyMap; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.atLeast; +import static org.mockito.Mockito.atLeastOnce; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +@SuppressWarnings({"rawtypes", "unchecked"}) +public class AMQPObservableQueueTest { + + final int batchSize = 10; + final int pollTimeMs = 500; + + Address[] addresses; + AMQPEventQueueProperties properties; + + @Before + public void setUp() { + properties = mock(AMQPEventQueueProperties.class); + when(properties.getBatchSize()).thenReturn(1); + when(properties.getPollTimeDuration()).thenReturn(Duration.ofMillis(100)); + when(properties.getHosts()).thenReturn(ConnectionFactory.DEFAULT_HOST); + when(properties.getUsername()).thenReturn(ConnectionFactory.DEFAULT_USER); + when(properties.getPassword()).thenReturn(ConnectionFactory.DEFAULT_PASS); + when(properties.getVirtualHost()).thenReturn(ConnectionFactory.DEFAULT_VHOST); + when(properties.getPort()).thenReturn(PROTOCOL.PORT); + when(properties.getConnectionTimeoutInMilliSecs()).thenReturn(60000); + when(properties.isUseNio()).thenReturn(false); + when(properties.isDurable()).thenReturn(true); + when(properties.isExclusive()).thenReturn(false); + when(properties.isAutoDelete()).thenReturn(false); + when(properties.getContentType()).thenReturn("application/json"); + when(properties.getContentEncoding()).thenReturn("UTF-8"); + when(properties.getExchangeType()).thenReturn("topic"); + when(properties.getDeliveryMode()).thenReturn(2); + when(properties.isUseExchange()).thenReturn(true); + addresses = new Address[] {new Address("localhost", PROTOCOL.PORT)}; + AMQPConnection.setAMQPConnection(null); + } + + List buildQueue(final Random random, final int bound) { + final LinkedList queue = new LinkedList(); + for (int i = 0; i < bound; i++) { + AMQP.BasicProperties props = mock(AMQP.BasicProperties.class); + when(props.getMessageId()).thenReturn(UUID.randomUUID().toString()); + Envelope envelope = mock(Envelope.class); + when(envelope.getDeliveryTag()).thenReturn(random.nextLong()); + GetResponse response = mock(GetResponse.class); + when(response.getProps()).thenReturn(props); + when(response.getEnvelope()).thenReturn(envelope); + when(response.getBody()).thenReturn("{}".getBytes()); + when(response.getMessageCount()).thenReturn(bound - i); + queue.add(response); + } + return queue; + } + + Channel mockBaseChannel() throws IOException, TimeoutException { + Channel channel = mock(Channel.class); + when(channel.isOpen()).thenReturn(Boolean.TRUE); + /* + * doAnswer(invocation -> { when(channel.isOpen()).thenReturn(Boolean.FALSE); + * return DoesNothing.doesNothing(); }).when(channel).close(); + */ + return channel; + } + + Channel mockChannelForQueue( + Channel channel, + boolean isWorking, + boolean exists, + String name, + List queue) + throws IOException { + // queueDeclarePassive + final AMQImpl.Queue.DeclareOk queueDeclareOK = + new AMQImpl.Queue.DeclareOk(name, queue.size(), 1); + if (exists) { + when(channel.queueDeclarePassive(eq(name))).thenReturn(queueDeclareOK); + } else { + when(channel.queueDeclarePassive(eq(name))) + .thenThrow(new IOException("Queue " + name + " exists")); + } + // queueDeclare + OngoingStubbing declareOkOngoingStubbing = + when(channel.queueDeclare( + eq(name), anyBoolean(), anyBoolean(), anyBoolean(), anyMap())) + .thenReturn(queueDeclareOK); + if (!isWorking) { + declareOkOngoingStubbing.thenThrow( + new IOException("Cannot declare queue " + name), + new RuntimeException("Not working")); + } + // messageCount + when(channel.messageCount(eq(name))).thenReturn((long) queue.size()); + // basicGet + OngoingStubbing getResponseOngoingStubbing = + Mockito.when(channel.basicConsume(eq(name), anyBoolean(), any(Consumer.class))) + .thenReturn(name); + if (!isWorking) { + getResponseOngoingStubbing.thenThrow( + new IOException("Not working"), new RuntimeException("Not working")); + } + // basicPublish + if (isWorking) { + doNothing() + .when(channel) + .basicPublish( + eq(StringUtils.EMPTY), + eq(name), + any(AMQP.BasicProperties.class), + any(byte[].class)); + } else { + doThrow(new IOException("Not working")) + .when(channel) + .basicPublish( + eq(StringUtils.EMPTY), + eq(name), + any(AMQP.BasicProperties.class), + any(byte[].class)); + } + return channel; + } + + Channel mockChannelForExchange( + Channel channel, + boolean isWorking, + boolean exists, + String queueName, + String name, + String type, + String routingKey, + List queue) + throws IOException { + // exchangeDeclarePassive + final AMQImpl.Exchange.DeclareOk exchangeDeclareOK = new AMQImpl.Exchange.DeclareOk(); + if (exists) { + when(channel.exchangeDeclarePassive(eq(name))).thenReturn(exchangeDeclareOK); + } else { + when(channel.exchangeDeclarePassive(eq(name))) + .thenThrow(new IOException("Exchange " + name + " exists")); + } + // exchangeDeclare + OngoingStubbing declareOkOngoingStubbing = + when(channel.exchangeDeclare( + eq(name), eq(type), anyBoolean(), anyBoolean(), anyMap())) + .thenReturn(exchangeDeclareOK); + if (!isWorking) { + declareOkOngoingStubbing.thenThrow( + new IOException("Cannot declare exchange " + name + " of type " + type), + new RuntimeException("Not working")); + } + // queueDeclarePassive + final AMQImpl.Queue.DeclareOk queueDeclareOK = + new AMQImpl.Queue.DeclareOk(queueName, queue.size(), 1); + if (exists) { + when(channel.queueDeclarePassive(eq(queueName))).thenReturn(queueDeclareOK); + } else { + when(channel.queueDeclarePassive(eq(queueName))) + .thenThrow(new IOException("Queue " + queueName + " exists")); + } + // queueDeclare + when(channel.queueDeclare( + eq(queueName), anyBoolean(), anyBoolean(), anyBoolean(), anyMap())) + .thenReturn(queueDeclareOK); + // queueBind + when(channel.queueBind(eq(queueName), eq(name), eq(routingKey))) + .thenReturn(new AMQImpl.Queue.BindOk()); + // messageCount + when(channel.messageCount(eq(name))).thenReturn((long) queue.size()); + // basicGet + + OngoingStubbing getResponseOngoingStubbing = + Mockito.when(channel.basicConsume(eq(queueName), anyBoolean(), any(Consumer.class))) + .thenReturn(queueName); + + if (!isWorking) { + getResponseOngoingStubbing.thenThrow( + new IOException("Not working"), new RuntimeException("Not working")); + } + // basicPublish + if (isWorking) { + doNothing() + .when(channel) + .basicPublish( + eq(name), + eq(routingKey), + any(AMQP.BasicProperties.class), + any(byte[].class)); + } else { + doThrow(new IOException("Not working")) + .when(channel) + .basicPublish( + eq(name), + eq(routingKey), + any(AMQP.BasicProperties.class), + any(byte[].class)); + } + return channel; + } + + Connection mockGoodConnection(Channel channel) throws IOException { + Connection connection = mock(Connection.class); + when(connection.createChannel()).thenReturn(channel); + when(connection.isOpen()).thenReturn(Boolean.TRUE); + /* + * doAnswer(invocation -> { when(connection.isOpen()).thenReturn(Boolean.FALSE); + * return DoesNothing.doesNothing(); }).when(connection).close(); + */ return connection; + } + + Connection mockBadConnection() throws IOException { + Connection connection = mock(Connection.class); + when(connection.createChannel()).thenThrow(new IOException("Can't create channel")); + when(connection.isOpen()).thenReturn(Boolean.TRUE); + doThrow(new IOException("Can't close connection")).when(connection).close(); + return connection; + } + + ConnectionFactory mockConnectionFactory(Connection connection) + throws IOException, TimeoutException { + ConnectionFactory connectionFactory = mock(ConnectionFactory.class); + when(connectionFactory.newConnection(eq(addresses), Mockito.anyString())) + .thenReturn(connection); + return connectionFactory; + } + + void runObserve( + Channel channel, + AMQPObservableQueue observableQueue, + String queueName, + boolean useWorkingChannel, + int batchSize) + throws IOException { + + final List found = new ArrayList<>(batchSize); + TestSubscriber subscriber = TestSubscriber.create(Subscribers.create(found::add)); + rx.Observable observable = + observableQueue.observe().take(pollTimeMs * 2, TimeUnit.MILLISECONDS); + assertNotNull(observable); + observable.subscribe(subscriber); + subscriber.awaitTerminalEvent(); + subscriber.assertNoErrors(); + subscriber.assertCompleted(); + if (useWorkingChannel) { + verify(channel, atLeast(1)) + .basicConsume(eq(queueName), anyBoolean(), any(Consumer.class)); + doNothing().when(channel).basicAck(anyLong(), eq(false)); + doAnswer(DoesNothing.doesNothing()).when(channel).basicAck(anyLong(), eq(false)); + observableQueue.ack(Collections.synchronizedList(found)); + } else { + assertNotNull(found); + assertTrue(found.isEmpty()); + } + observableQueue.close(); + } + + @Test + public void + testGetMessagesFromExistingExchangeWithDurableExclusiveAutoDeleteQueueConfiguration() + throws IOException, TimeoutException { + // Mock channel and connection + Channel channel = mockBaseChannel(); + Connection connection = mockGoodConnection(channel); + testGetMessagesFromExchangeAndCustomConfigurationFromURI( + channel, connection, true, true, true, true, true); + } + + @Test + public void testGetMessagesFromExistingExchangeWithDefaultConfiguration() + throws IOException, TimeoutException { + // Mock channel and connection + Channel channel = mockBaseChannel(); + Connection connection = mockGoodConnection(channel); + testGetMessagesFromExchangeAndDefaultConfiguration(channel, connection, true, true); + } + + @Test + public void testPublishMessagesToNotExistingExchangeAndDefaultConfiguration() + throws IOException, TimeoutException { + // Mock channel and connection + Channel channel = mockBaseChannel(); + Connection connection = mockGoodConnection(channel); + testPublishMessagesToExchangeAndDefaultConfiguration(channel, connection, false, true); + } + + @Test + public void testAck() throws IOException, TimeoutException { + // Mock channel and connection + Channel channel = mockBaseChannel(); + Connection connection = mockGoodConnection(channel); + final Random random = new Random(); + + final String name = RandomStringUtils.randomAlphabetic(30), + type = "topic", + routingKey = RandomStringUtils.randomAlphabetic(30); + AMQPRetryPattern retrySettings = null; + final AMQPSettings settings = + new AMQPSettings(properties) + .fromURI( + "amqp_exchange:" + + name + + "?exchangeType=" + + type + + "&routingKey=" + + routingKey); + AMQPObservableQueue observableQueue = + new AMQPObservableQueue( + mockConnectionFactory(connection), + addresses, + true, + settings, + retrySettings, + batchSize, + pollTimeMs); + List messages = new LinkedList<>(); + Message msg = new Message(); + msg.setId("0e3eef8f-ebb1-4244-9665-759ab5bdf433"); + msg.setPayload("Payload"); + msg.setReceipt("1"); + messages.add(msg); + List failedMessages = observableQueue.ack(messages); + assertNotNull(failedMessages); + assertTrue(failedMessages.isEmpty()); + } + + private void testGetMessagesFromExchangeAndDefaultConfiguration( + Channel channel, Connection connection, boolean exists, boolean useWorkingChannel) + throws IOException, TimeoutException { + + final Random random = new Random(); + + final String name = RandomStringUtils.randomAlphabetic(30), + type = "topic", + routingKey = RandomStringUtils.randomAlphabetic(30); + final String queueName = String.format("bound_to_%s", name); + + final AMQPSettings settings = + new AMQPSettings(properties) + .fromURI( + "amqp_exchange:" + + name + + "?exchangeType=" + + type + + "&routingKey=" + + routingKey); + assertTrue(settings.isDurable()); + assertFalse(settings.isExclusive()); + assertFalse(settings.autoDelete()); + assertEquals(2, settings.getDeliveryMode()); + assertEquals(name, settings.getQueueOrExchangeName()); + assertEquals(type, settings.getExchangeType()); + assertEquals(routingKey, settings.getRoutingKey()); + assertEquals(queueName, settings.getExchangeBoundQueueName()); + + List queue = buildQueue(random, batchSize); + channel = + mockChannelForExchange( + channel, + useWorkingChannel, + exists, + queueName, + name, + type, + routingKey, + queue); + AMQPRetryPattern retrySettings = null; + AMQPObservableQueue observableQueue = + new AMQPObservableQueue( + mockConnectionFactory(connection), + addresses, + true, + settings, + retrySettings, + batchSize, + pollTimeMs); + + assertArrayEquals(addresses, observableQueue.getAddresses()); + assertEquals(AMQPConstants.AMQP_EXCHANGE_TYPE, observableQueue.getType()); + assertEquals( + AMQPConstants.AMQP_EXCHANGE_TYPE + + ":" + + name + + "?exchangeType=" + + type + + "&routingKey=" + + routingKey, + observableQueue.getName()); + assertEquals(name, observableQueue.getURI()); + assertEquals(batchSize, observableQueue.getBatchSize()); + assertEquals(pollTimeMs, observableQueue.getPollTimeInMS()); + assertEquals(queue.size(), observableQueue.size()); + + runObserve(channel, observableQueue, queueName, useWorkingChannel, batchSize); + + if (useWorkingChannel) { + verify(channel, atLeastOnce()) + .exchangeDeclare( + eq(name), + eq(type), + eq(settings.isDurable()), + eq(settings.autoDelete()), + eq(Collections.emptyMap())); + verify(channel, atLeastOnce()) + .queueDeclare( + eq(queueName), + eq(settings.isDurable()), + eq(settings.isExclusive()), + eq(settings.autoDelete()), + anyMap()); + + verify(channel, atLeastOnce()).queueBind(eq(queueName), eq(name), eq(routingKey)); + } + } + + private void testGetMessagesFromExchangeAndCustomConfigurationFromURI( + Channel channel, + Connection connection, + boolean exists, + boolean useWorkingChannel, + boolean durable, + boolean exclusive, + boolean autoDelete) + throws IOException, TimeoutException { + + final Random random = new Random(); + + final String name = RandomStringUtils.randomAlphabetic(30), + type = "topic", + routingKey = RandomStringUtils.randomAlphabetic(30); + final String queueName = String.format("bound_to_%s", name); + + final AMQPSettings settings = + new AMQPSettings(properties) + .fromURI( + "amqp_exchange:" + + name + + "?exchangeType=" + + type + + "&bindQueueName=" + + queueName + + "&routingKey=" + + routingKey + + "&deliveryMode=2" + + "&durable=" + + durable + + "&exclusive=" + + exclusive + + "&autoDelete=" + + autoDelete); + assertEquals(durable, settings.isDurable()); + assertEquals(exclusive, settings.isExclusive()); + assertEquals(autoDelete, settings.autoDelete()); + assertEquals(2, settings.getDeliveryMode()); + assertEquals(name, settings.getQueueOrExchangeName()); + assertEquals(type, settings.getExchangeType()); + assertEquals(queueName, settings.getExchangeBoundQueueName()); + assertEquals(routingKey, settings.getRoutingKey()); + + List queue = buildQueue(random, batchSize); + channel = + mockChannelForExchange( + channel, + useWorkingChannel, + exists, + queueName, + name, + type, + routingKey, + queue); + AMQPRetryPattern retrySettings = null; + AMQPObservableQueue observableQueue = + new AMQPObservableQueue( + mockConnectionFactory(connection), + addresses, + true, + settings, + retrySettings, + batchSize, + pollTimeMs); + + assertArrayEquals(addresses, observableQueue.getAddresses()); + assertEquals(AMQPConstants.AMQP_EXCHANGE_TYPE, observableQueue.getType()); + assertEquals( + AMQPConstants.AMQP_EXCHANGE_TYPE + + ":" + + name + + "?exchangeType=" + + type + + "&bindQueueName=" + + queueName + + "&routingKey=" + + routingKey + + "&deliveryMode=2" + + "&durable=" + + durable + + "&exclusive=" + + exclusive + + "&autoDelete=" + + autoDelete, + observableQueue.getName()); + assertEquals(name, observableQueue.getURI()); + assertEquals(batchSize, observableQueue.getBatchSize()); + assertEquals(pollTimeMs, observableQueue.getPollTimeInMS()); + assertEquals(queue.size(), observableQueue.size()); + + runObserve(channel, observableQueue, queueName, useWorkingChannel, batchSize); + + if (useWorkingChannel) { + verify(channel, atLeastOnce()) + .exchangeDeclare( + eq(name), + eq(type), + eq(settings.isDurable()), + eq(settings.autoDelete()), + eq(Collections.emptyMap())); + verify(channel, atLeastOnce()) + .queueDeclare( + eq(queueName), + eq(settings.isDurable()), + eq(settings.isExclusive()), + eq(settings.autoDelete()), + anyMap()); + + verify(channel, atLeastOnce()).queueBind(eq(queueName), eq(name), eq(routingKey)); + } + } + + private void testPublishMessagesToExchangeAndDefaultConfiguration( + Channel channel, Connection connection, boolean exists, boolean useWorkingChannel) + throws IOException, TimeoutException { + final Random random = new Random(); + + final String name = RandomStringUtils.randomAlphabetic(30), + type = "topic", + queueName = RandomStringUtils.randomAlphabetic(30), + routingKey = RandomStringUtils.randomAlphabetic(30); + + final AMQPSettings settings = + new AMQPSettings(properties) + .fromURI( + "amqp_exchange:" + + name + + "?exchangeType=" + + type + + "&routingKey=" + + routingKey + + "&deliveryMode=2&durable=true&exclusive=false&autoDelete=true"); + assertTrue(settings.isDurable()); + assertFalse(settings.isExclusive()); + assertTrue(settings.autoDelete()); + assertEquals(2, settings.getDeliveryMode()); + assertEquals(name, settings.getQueueOrExchangeName()); + assertEquals(type, settings.getExchangeType()); + assertEquals(routingKey, settings.getRoutingKey()); + + List queue = buildQueue(random, batchSize); + channel = + mockChannelForExchange( + channel, + useWorkingChannel, + exists, + queueName, + name, + type, + routingKey, + queue); + AMQPRetryPattern retrySettings = null; + AMQPObservableQueue observableQueue = + new AMQPObservableQueue( + mockConnectionFactory(connection), + addresses, + true, + settings, + retrySettings, + batchSize, + pollTimeMs); + + assertArrayEquals(addresses, observableQueue.getAddresses()); + assertEquals(AMQPConstants.AMQP_EXCHANGE_TYPE, observableQueue.getType()); + assertEquals( + AMQPConstants.AMQP_EXCHANGE_TYPE + + ":" + + name + + "?exchangeType=" + + type + + "&routingKey=" + + routingKey + + "&deliveryMode=2&durable=true&exclusive=false&autoDelete=true", + observableQueue.getName()); + assertEquals(name, observableQueue.getURI()); + assertEquals(batchSize, observableQueue.getBatchSize()); + assertEquals(pollTimeMs, observableQueue.getPollTimeInMS()); + assertEquals(queue.size(), observableQueue.size()); + + List messages = new LinkedList<>(); + Observable.range(0, batchSize) + .forEach((Integer x) -> messages.add(new Message("" + x, "payload: " + x, null))); + assertEquals(batchSize, messages.size()); + observableQueue.publish(messages); + + if (useWorkingChannel) { + verify(channel, times(batchSize)) + .basicPublish( + eq(name), + eq(routingKey), + any(AMQP.BasicProperties.class), + any(byte[].class)); + } + } + + @Test + public void testGetMessagesFromExistingQueueAndDefaultConfiguration() + throws IOException, TimeoutException { + // Mock channel and connection + Channel channel = mockBaseChannel(); + Connection connection = mockGoodConnection(channel); + testGetMessagesFromQueueAndDefaultConfiguration(channel, connection, true, true); + } + + @Test + public void testGetMessagesFromNotExistingQueueAndDefaultConfiguration() + throws IOException, TimeoutException { + // Mock channel and connection + Channel channel = mockBaseChannel(); + Connection connection = mockGoodConnection(channel); + testGetMessagesFromQueueAndDefaultConfiguration(channel, connection, false, true); + } + + @Test + public void testGetMessagesFromQueueWithBadChannel() throws IOException, TimeoutException { + // Mock channel and connection + Channel channel = mockBaseChannel(); + Connection connection = mockGoodConnection(channel); + testGetMessagesFromQueueAndDefaultConfiguration(channel, connection, true, false); + } + + @Test(expected = RuntimeException.class) + public void testPublishMessagesToQueueWithBadChannel() throws IOException, TimeoutException { + // Mock channel and connection + Channel channel = mockBaseChannel(); + Connection connection = mockGoodConnection(channel); + testPublishMessagesToQueueAndDefaultConfiguration(channel, connection, true, false); + } + + @Test(expected = IllegalArgumentException.class) + public void testAMQPObservalbleQueue_empty() throws IOException, TimeoutException { + AMQPSettings settings = new AMQPSettings(properties).fromURI("amqp_queue:test"); + AMQPRetryPattern retrySettings = null; + AMQPObservableQueue observableQueue = + new AMQPObservableQueue( + null, addresses, false, settings, retrySettings, batchSize, pollTimeMs); + } + + @Test(expected = IllegalArgumentException.class) + public void testAMQPObservalbleQueue_addressEmpty() throws IOException, TimeoutException { + AMQPSettings settings = new AMQPSettings(properties).fromURI("amqp_queue:test"); + AMQPRetryPattern retrySettings = null; + AMQPObservableQueue observableQueue = + new AMQPObservableQueue( + mockConnectionFactory(mockGoodConnection(mockBaseChannel())), + null, + false, + settings, + retrySettings, + batchSize, + pollTimeMs); + } + + @Test(expected = IllegalArgumentException.class) + public void testAMQPObservalbleQueue_settingsEmpty() throws IOException, TimeoutException { + AMQPRetryPattern retrySettings = null; + AMQPObservableQueue observableQueue = + new AMQPObservableQueue( + mockConnectionFactory(mockGoodConnection(mockBaseChannel())), + addresses, + false, + null, + retrySettings, + batchSize, + pollTimeMs); + } + + @Test(expected = IllegalArgumentException.class) + public void testAMQPObservalbleQueue_batchsizezero() throws IOException, TimeoutException { + AMQPSettings settings = new AMQPSettings(properties).fromURI("amqp_queue:test"); + AMQPRetryPattern retrySettings = null; + AMQPObservableQueue observableQueue = + new AMQPObservableQueue( + mockConnectionFactory(mockGoodConnection(mockBaseChannel())), + addresses, + false, + settings, + retrySettings, + 0, + pollTimeMs); + } + + @Test(expected = IllegalArgumentException.class) + public void testAMQPObservalbleQueue_polltimezero() throws IOException, TimeoutException { + AMQPSettings settings = new AMQPSettings(properties).fromURI("amqp_queue:test"); + AMQPRetryPattern retrySettings = null; + AMQPObservableQueue observableQueue = + new AMQPObservableQueue( + mockConnectionFactory(mockGoodConnection(mockBaseChannel())), + addresses, + false, + settings, + retrySettings, + batchSize, + 0); + } + + @Test + public void testclosetExistingQueueAndDefaultConfiguration() + throws IOException, TimeoutException { + // Mock channel and connection + Channel channel = mockBaseChannel(); + Connection connection = mockGoodConnection(channel); + testGetMessagesFromQueueAndDefaultConfiguration_close(channel, connection, false, true); + } + + private void testGetMessagesFromQueueAndDefaultConfiguration( + Channel channel, Connection connection, boolean queueExists, boolean useWorkingChannel) + throws IOException, TimeoutException { + final Random random = new Random(); + + final String queueName = RandomStringUtils.randomAlphabetic(30); + AMQPSettings settings = new AMQPSettings(properties).fromURI("amqp_queue:" + queueName); + + List queue = buildQueue(random, batchSize); + channel = mockChannelForQueue(channel, useWorkingChannel, queueExists, queueName, queue); + AMQPRetryPattern retrySettings = null; + AMQPObservableQueue observableQueue = + new AMQPObservableQueue( + mockConnectionFactory(connection), + addresses, + false, + settings, + retrySettings, + batchSize, + pollTimeMs); + + assertArrayEquals(addresses, observableQueue.getAddresses()); + assertEquals(AMQPConstants.AMQP_QUEUE_TYPE, observableQueue.getType()); + assertEquals(AMQPConstants.AMQP_QUEUE_TYPE + ":" + queueName, observableQueue.getName()); + assertEquals(queueName, observableQueue.getURI()); + assertEquals(batchSize, observableQueue.getBatchSize()); + assertEquals(pollTimeMs, observableQueue.getPollTimeInMS()); + assertEquals(queue.size(), observableQueue.size()); + + runObserve(channel, observableQueue, queueName, useWorkingChannel, batchSize); + } + + private void testGetMessagesFromQueueAndDefaultConfiguration_close( + Channel channel, Connection connection, boolean queueExists, boolean useWorkingChannel) + throws IOException, TimeoutException { + final Random random = new Random(); + + final String queueName = RandomStringUtils.randomAlphabetic(30); + AMQPSettings settings = new AMQPSettings(properties).fromURI("amqp_queue:" + queueName); + + List queue = buildQueue(random, batchSize); + channel = mockChannelForQueue(channel, useWorkingChannel, queueExists, queueName, queue); + AMQPRetryPattern retrySettings = null; + AMQPObservableQueue observableQueue = + new AMQPObservableQueue( + mockConnectionFactory(connection), + addresses, + false, + settings, + retrySettings, + batchSize, + pollTimeMs); + observableQueue.close(); + assertArrayEquals(addresses, observableQueue.getAddresses()); + assertEquals(AMQPConstants.AMQP_QUEUE_TYPE, observableQueue.getType()); + assertEquals(AMQPConstants.AMQP_QUEUE_TYPE + ":" + queueName, observableQueue.getName()); + assertEquals(queueName, observableQueue.getURI()); + assertEquals(batchSize, observableQueue.getBatchSize()); + assertEquals(pollTimeMs, observableQueue.getPollTimeInMS()); + assertEquals(queue.size(), observableQueue.size()); + } + + private void testPublishMessagesToQueueAndDefaultConfiguration( + Channel channel, Connection connection, boolean queueExists, boolean useWorkingChannel) + throws IOException, TimeoutException { + final Random random = new Random(); + + final String queueName = RandomStringUtils.randomAlphabetic(30); + final AMQPSettings settings = + new AMQPSettings(properties) + .fromURI( + "amqp_queue:" + + queueName + + "?deliveryMode=2&durable=true&exclusive=false&autoDelete=true"); + assertTrue(settings.isDurable()); + assertFalse(settings.isExclusive()); + assertTrue(settings.autoDelete()); + assertEquals(2, settings.getDeliveryMode()); + + List queue = buildQueue(random, batchSize); + channel = mockChannelForQueue(channel, useWorkingChannel, queueExists, queueName, queue); + AMQPRetryPattern retrySettings = new AMQPRetryPattern(3, 5, RetryType.REGULARINTERVALS); + AMQPObservableQueue observableQueue = + new AMQPObservableQueue( + mockConnectionFactory(connection), + addresses, + false, + settings, + retrySettings, + batchSize, + pollTimeMs); + + assertArrayEquals(addresses, observableQueue.getAddresses()); + assertEquals(AMQPConstants.AMQP_QUEUE_TYPE, observableQueue.getType()); + assertEquals( + AMQPConstants.AMQP_QUEUE_TYPE + + ":" + + queueName + + "?deliveryMode=2&durable=true&exclusive=false&autoDelete=true", + observableQueue.getName()); + assertEquals(queueName, observableQueue.getURI()); + assertEquals(batchSize, observableQueue.getBatchSize()); + assertEquals(pollTimeMs, observableQueue.getPollTimeInMS()); + assertEquals(queue.size(), observableQueue.size()); + + List messages = new LinkedList<>(); + Observable.range(0, batchSize) + .forEach((Integer x) -> messages.add(new Message("" + x, "payload: " + x, null))); + assertEquals(batchSize, messages.size()); + observableQueue.publish(messages); + + if (useWorkingChannel) { + verify(channel, times(batchSize)) + .basicPublish( + eq(StringUtils.EMPTY), + eq(queueName), + any(AMQP.BasicProperties.class), + any(byte[].class)); + } + } +} diff --git a/amqp/src/test/java/com/netflix/conductor/contribs/queue/amqp/AMQPSettingsTest.java b/amqp/src/test/java/com/netflix/conductor/contribs/queue/amqp/AMQPSettingsTest.java new file mode 100644 index 000000000..a9c5f26f0 --- /dev/null +++ b/amqp/src/test/java/com/netflix/conductor/contribs/queue/amqp/AMQPSettingsTest.java @@ -0,0 +1,89 @@ +/* + * Copyright 2023 Conductor Authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package com.netflix.conductor.contribs.queue.amqp; + +import java.time.Duration; + +import org.junit.Before; +import org.junit.Test; + +import com.netflix.conductor.contribs.queue.amqp.config.AMQPEventQueueProperties; +import com.netflix.conductor.contribs.queue.amqp.util.AMQPSettings; + +import com.rabbitmq.client.AMQP.PROTOCOL; +import com.rabbitmq.client.ConnectionFactory; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class AMQPSettingsTest { + + private AMQPEventQueueProperties properties; + + @Before + public void setUp() { + properties = mock(AMQPEventQueueProperties.class); + when(properties.getBatchSize()).thenReturn(1); + when(properties.getPollTimeDuration()).thenReturn(Duration.ofMillis(100)); + when(properties.getHosts()).thenReturn(ConnectionFactory.DEFAULT_HOST); + when(properties.getUsername()).thenReturn(ConnectionFactory.DEFAULT_USER); + when(properties.getPassword()).thenReturn(ConnectionFactory.DEFAULT_PASS); + when(properties.getVirtualHost()).thenReturn(ConnectionFactory.DEFAULT_VHOST); + when(properties.getPort()).thenReturn(PROTOCOL.PORT); + when(properties.getConnectionTimeoutInMilliSecs()).thenReturn(60000); + when(properties.isUseNio()).thenReturn(false); + when(properties.isDurable()).thenReturn(true); + when(properties.isExclusive()).thenReturn(false); + when(properties.isAutoDelete()).thenReturn(false); + when(properties.getContentType()).thenReturn("application/json"); + when(properties.getContentEncoding()).thenReturn("UTF-8"); + when(properties.getExchangeType()).thenReturn("topic"); + when(properties.getDeliveryMode()).thenReturn(2); + when(properties.isUseExchange()).thenReturn(true); + } + + @Test + public void testAMQPSettings_exchange_fromuri_defaultconfig() { + String exchangestring = + "amqp_exchange:myExchangeName?exchangeType=topic&routingKey=test&deliveryMode=2"; + AMQPSettings settings = new AMQPSettings(properties); + settings.fromURI(exchangestring); + assertEquals("topic", settings.getExchangeType()); + assertEquals("test", settings.getRoutingKey()); + assertEquals("myExchangeName", settings.getQueueOrExchangeName()); + } + + @Test + public void testAMQPSettings_queue_fromuri_defaultconfig() { + String exchangestring = + "amqp_queue:myQueueName?deliveryMode=2&durable=false&autoDelete=true&exclusive=true"; + AMQPSettings settings = new AMQPSettings(properties); + settings.fromURI(exchangestring); + assertFalse(settings.isDurable()); + assertTrue(settings.isExclusive()); + assertTrue(settings.autoDelete()); + assertEquals(2, settings.getDeliveryMode()); + assertEquals("myQueueName", settings.getQueueOrExchangeName()); + } + + @Test(expected = IllegalArgumentException.class) + public void testAMQPSettings_exchange_fromuri_wrongdeliverymode() { + String exchangestring = + "amqp_exchange:myExchangeName?exchangeType=topic&routingKey=test&deliveryMode=3"; + AMQPSettings settings = new AMQPSettings(properties); + settings.fromURI(exchangestring); + } +} diff --git a/annotations-processor/README.md b/annotations-processor/README.md index 13ec4a3d0..75dfca351 100644 --- a/annotations-processor/README.md +++ b/annotations-processor/README.md @@ -1 +1 @@ -[Annotations Processor](docs/docs/reference-docs/annotations-processor.md) \ No newline at end of file +Annotation processor is used to generate protobuf files from the annotations. diff --git a/annotations-processor/build.gradle b/annotations-processor/build.gradle index 008983429..18844ab09 100644 --- a/annotations-processor/build.gradle +++ b/annotations-processor/build.gradle @@ -5,11 +5,11 @@ sourceSets { dependencies { implementation project(':conductor-annotations') - api 'com.google.guava:guava:32.1.2-jre' - api 'com.squareup:javapoet:1.13.+' - api 'com.github.jknack:handlebars:4.3.+' + api 'com.google.guava:guava:31.1-jre' + api 'com.squareup:javapoet:1.13.0' + api 'com.github.jknack:handlebars:4.3.1' api 'com.google.protobuf:protobuf-java:3.21.12' - api 'javax.annotation:javax.annotation-api:1.3.2' + api 'jakarta.annotation:jakarta.annotation-api:2.1.1' api gradleApi() exampleImplementation sourceSets.main.output diff --git a/annotations-processor/dependencies.lock b/annotations-processor/dependencies.lock deleted file mode 100644 index 1c9fbc411..000000000 --- a/annotations-processor/dependencies.lock +++ /dev/null @@ -1,535 +0,0 @@ -{ - "annotationProcessor": { - "org.springframework.boot:spring-boot-configuration-processor": { - "locked": "2.7.16" - } - }, - "compileClasspath": { - "com.fasterxml.jackson.core:jackson-annotations": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.core:jackson-core": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.core:jackson-databind": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.dataformat:jackson-dataformat-cbor": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.dataformat:jackson-dataformat-smile": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.dataformat:jackson-dataformat-yaml": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.datatype:jackson-datatype-jdk8": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.datatype:jackson-datatype-joda": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.datatype:jackson-datatype-jsr310": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.module:jackson-module-afterburner": { - "locked": "2.15.0" - }, - "com.github.jknack:handlebars": { - "locked": "4.3.1" - }, - "com.google.guava:guava": { - "locked": "32.1.2-jre" - }, - "com.google.protobuf:protobuf-java": { - "locked": "3.21.12" - }, - "com.netflix.conductor:conductor-annotations": { - "project": true - }, - "com.squareup:javapoet": { - "locked": "1.13.0" - }, - "javax.annotation:javax.annotation-api": { - "locked": "1.3.2" - }, - "org.apache.logging.log4j:log4j-api": { - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-core": { - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-jul": { - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-slf4j-impl": { - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-web": { - "locked": "2.17.2" - }, - "org.yaml:snakeyaml": { - "locked": "2.0" - } - }, - "exampleCompileClasspath": { - "com.netflix.conductor:conductor-annotations": { - "project": true - } - }, - "exampleRuntimeClasspath": { - "com.fasterxml.jackson.core:jackson-annotations": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations" - ], - "locked": "2.13.5" - }, - "com.fasterxml.jackson.core:jackson-core": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations" - ], - "locked": "2.13.5" - }, - "com.fasterxml.jackson.core:jackson-databind": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations" - ], - "locked": "2.13.5" - }, - "com.fasterxml.jackson.dataformat:jackson-dataformat-cbor": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations" - ], - "locked": "2.13.5" - }, - "com.fasterxml.jackson.dataformat:jackson-dataformat-smile": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations" - ], - "locked": "2.13.5" - }, - "com.fasterxml.jackson.dataformat:jackson-dataformat-yaml": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations" - ], - "locked": "2.13.5" - }, - "com.fasterxml.jackson.datatype:jackson-datatype-jdk8": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations" - ], - "locked": "2.13.5" - }, - "com.fasterxml.jackson.datatype:jackson-datatype-joda": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations" - ], - "locked": "2.13.5" - }, - "com.fasterxml.jackson.datatype:jackson-datatype-jsr310": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations" - ], - "locked": "2.13.5" - }, - "com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations" - ], - "locked": "2.13.5" - }, - "com.fasterxml.jackson.module:jackson-module-afterburner": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations" - ], - "locked": "2.13.5" - }, - "com.netflix.conductor:conductor-annotations": { - "project": true - }, - "org.apache.logging.log4j:log4j-api": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations" - ], - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-core": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations" - ], - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-jul": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations" - ], - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-slf4j-impl": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations" - ], - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-web": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations" - ], - "locked": "2.17.2" - }, - "org.yaml:snakeyaml": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations" - ], - "locked": "1.30" - } - }, - "runtimeClasspath": { - "com.fasterxml.jackson.core:jackson-annotations": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.core:jackson-core": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.core:jackson-databind": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.dataformat:jackson-dataformat-cbor": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.dataformat:jackson-dataformat-smile": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.dataformat:jackson-dataformat-yaml": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.datatype:jackson-datatype-jdk8": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.datatype:jackson-datatype-joda": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.datatype:jackson-datatype-jsr310": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.module:jackson-module-afterburner": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations" - ], - "locked": "2.15.0" - }, - "com.github.jknack:handlebars": { - "locked": "4.3.1" - }, - "com.google.guava:guava": { - "locked": "32.1.2-jre" - }, - "com.google.protobuf:protobuf-java": { - "locked": "3.21.12" - }, - "com.netflix.conductor:conductor-annotations": { - "project": true - }, - "com.squareup:javapoet": { - "locked": "1.13.0" - }, - "javax.annotation:javax.annotation-api": { - "locked": "1.3.2" - }, - "org.apache.logging.log4j:log4j-api": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations" - ], - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-core": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations" - ], - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-jul": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations" - ], - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-slf4j-impl": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations" - ], - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-web": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations" - ], - "locked": "2.17.2" - }, - "org.yaml:snakeyaml": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations" - ], - "locked": "2.0" - } - }, - "testCompileClasspath": { - "com.fasterxml.jackson.core:jackson-annotations": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.core:jackson-core": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.core:jackson-databind": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.dataformat:jackson-dataformat-cbor": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.dataformat:jackson-dataformat-smile": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.dataformat:jackson-dataformat-yaml": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.datatype:jackson-datatype-jdk8": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.datatype:jackson-datatype-joda": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.datatype:jackson-datatype-jsr310": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.module:jackson-module-afterburner": { - "locked": "2.15.0" - }, - "com.github.jknack:handlebars": { - "locked": "4.3.1" - }, - "com.google.guava:guava": { - "locked": "32.1.2-jre" - }, - "com.google.protobuf:protobuf-java": { - "locked": "3.21.12" - }, - "com.netflix.conductor:conductor-annotations": { - "project": true - }, - "com.squareup:javapoet": { - "locked": "1.13.0" - }, - "javax.annotation:javax.annotation-api": { - "locked": "1.3.2" - }, - "junit:junit": { - "locked": "4.13.2" - }, - "net.java.dev.jna:jna": { - "locked": "5.13.0" - }, - "org.apache.logging.log4j:log4j-api": { - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-core": { - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-jul": { - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-slf4j-impl": { - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-web": { - "locked": "2.17.2" - }, - "org.junit.vintage:junit-vintage-engine": { - "locked": "5.8.2" - }, - "org.springframework.boot:spring-boot-starter-log4j2": { - "locked": "2.7.16" - }, - "org.springframework.boot:spring-boot-starter-test": { - "locked": "2.7.16" - }, - "org.yaml:snakeyaml": { - "locked": "2.0" - } - }, - "testRuntimeClasspath": { - "com.fasterxml.jackson.core:jackson-annotations": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.core:jackson-core": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.core:jackson-databind": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.dataformat:jackson-dataformat-cbor": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.dataformat:jackson-dataformat-smile": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.dataformat:jackson-dataformat-yaml": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.datatype:jackson-datatype-jdk8": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.datatype:jackson-datatype-joda": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.datatype:jackson-datatype-jsr310": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.module:jackson-module-afterburner": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations" - ], - "locked": "2.15.0" - }, - "com.github.jknack:handlebars": { - "locked": "4.3.1" - }, - "com.google.guava:guava": { - "locked": "32.1.2-jre" - }, - "com.google.protobuf:protobuf-java": { - "locked": "3.21.12" - }, - "com.netflix.conductor:conductor-annotations": { - "project": true - }, - "com.squareup:javapoet": { - "locked": "1.13.0" - }, - "javax.annotation:javax.annotation-api": { - "locked": "1.3.2" - }, - "junit:junit": { - "locked": "4.13.2" - }, - "net.java.dev.jna:jna": { - "locked": "5.13.0" - }, - "org.apache.logging.log4j:log4j-api": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations" - ], - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-core": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations" - ], - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-jul": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations" - ], - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-slf4j-impl": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations" - ], - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-web": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations" - ], - "locked": "2.17.2" - }, - "org.junit.vintage:junit-vintage-engine": { - "locked": "5.8.2" - }, - "org.springframework.boot:spring-boot-starter-log4j2": { - "locked": "2.7.16" - }, - "org.springframework.boot:spring-boot-starter-test": { - "locked": "2.7.16" - }, - "org.yaml:snakeyaml": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations" - ], - "locked": "2.0" - } - } -} \ No newline at end of file diff --git a/annotations-processor/src/example/java/com/example/Example.java b/annotations-processor/src/example/java/com/example/Example.java index b3c7befe8..f55cfac6e 100644 --- a/annotations-processor/src/example/java/com/example/Example.java +++ b/annotations-processor/src/example/java/com/example/Example.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/annotations-processor/src/main/java/com/netflix/conductor/annotationsprocessor/protogen/AbstractMessage.java b/annotations-processor/src/main/java/com/netflix/conductor/annotationsprocessor/protogen/AbstractMessage.java index bc92d901f..3794a7ca0 100644 --- a/annotations-processor/src/main/java/com/netflix/conductor/annotationsprocessor/protogen/AbstractMessage.java +++ b/annotations-processor/src/main/java/com/netflix/conductor/annotationsprocessor/protogen/AbstractMessage.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/annotations-processor/src/main/java/com/netflix/conductor/annotationsprocessor/protogen/Enum.java b/annotations-processor/src/main/java/com/netflix/conductor/annotationsprocessor/protogen/Enum.java index 3944bafb1..d1b4564bd 100644 --- a/annotations-processor/src/main/java/com/netflix/conductor/annotationsprocessor/protogen/Enum.java +++ b/annotations-processor/src/main/java/com/netflix/conductor/annotationsprocessor/protogen/Enum.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/annotations-processor/src/main/java/com/netflix/conductor/annotationsprocessor/protogen/Message.java b/annotations-processor/src/main/java/com/netflix/conductor/annotationsprocessor/protogen/Message.java index 9dfaf2883..ba6b1122b 100644 --- a/annotations-processor/src/main/java/com/netflix/conductor/annotationsprocessor/protogen/Message.java +++ b/annotations-processor/src/main/java/com/netflix/conductor/annotationsprocessor/protogen/Message.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/annotations-processor/src/main/java/com/netflix/conductor/annotationsprocessor/protogen/ProtoFile.java b/annotations-processor/src/main/java/com/netflix/conductor/annotationsprocessor/protogen/ProtoFile.java index 1bd543a60..e562c0f88 100644 --- a/annotations-processor/src/main/java/com/netflix/conductor/annotationsprocessor/protogen/ProtoFile.java +++ b/annotations-processor/src/main/java/com/netflix/conductor/annotationsprocessor/protogen/ProtoFile.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/annotations-processor/src/main/java/com/netflix/conductor/annotationsprocessor/protogen/ProtoGen.java b/annotations-processor/src/main/java/com/netflix/conductor/annotationsprocessor/protogen/ProtoGen.java index a2550d369..a2716eb3f 100644 --- a/annotations-processor/src/main/java/com/netflix/conductor/annotationsprocessor/protogen/ProtoGen.java +++ b/annotations-processor/src/main/java/com/netflix/conductor/annotationsprocessor/protogen/ProtoGen.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at @@ -20,7 +20,6 @@ import java.net.URLClassLoader; import java.util.*; -import javax.annotation.Generated; import javax.lang.model.element.Modifier; import com.netflix.conductor.annotations.protogen.ProtoMessage; @@ -35,6 +34,7 @@ import com.squareup.javapoet.JavaFile; import com.squareup.javapoet.MethodSpec; import com.squareup.javapoet.TypeSpec; +import jakarta.annotation.Generated; public class ProtoGen { private static final String GENERATOR_NAME = diff --git a/annotations-processor/src/main/java/com/netflix/conductor/annotationsprocessor/protogen/ProtoGenTask.java b/annotations-processor/src/main/java/com/netflix/conductor/annotationsprocessor/protogen/ProtoGenTask.java index fb411fc4f..d161d6ffb 100644 --- a/annotations-processor/src/main/java/com/netflix/conductor/annotationsprocessor/protogen/ProtoGenTask.java +++ b/annotations-processor/src/main/java/com/netflix/conductor/annotationsprocessor/protogen/ProtoGenTask.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/annotations-processor/src/main/java/com/netflix/conductor/annotationsprocessor/protogen/types/AbstractType.java b/annotations-processor/src/main/java/com/netflix/conductor/annotationsprocessor/protogen/types/AbstractType.java index fbfa8e72c..6a38fd551 100644 --- a/annotations-processor/src/main/java/com/netflix/conductor/annotationsprocessor/protogen/types/AbstractType.java +++ b/annotations-processor/src/main/java/com/netflix/conductor/annotationsprocessor/protogen/types/AbstractType.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/annotations-processor/src/main/java/com/netflix/conductor/annotationsprocessor/protogen/types/ExternMessageType.java b/annotations-processor/src/main/java/com/netflix/conductor/annotationsprocessor/protogen/types/ExternMessageType.java index ed7eaae24..93279d515 100644 --- a/annotations-processor/src/main/java/com/netflix/conductor/annotationsprocessor/protogen/types/ExternMessageType.java +++ b/annotations-processor/src/main/java/com/netflix/conductor/annotationsprocessor/protogen/types/ExternMessageType.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/annotations-processor/src/main/java/com/netflix/conductor/annotationsprocessor/protogen/types/GenericType.java b/annotations-processor/src/main/java/com/netflix/conductor/annotationsprocessor/protogen/types/GenericType.java index 5bad20a2f..adf8f4d8f 100644 --- a/annotations-processor/src/main/java/com/netflix/conductor/annotationsprocessor/protogen/types/GenericType.java +++ b/annotations-processor/src/main/java/com/netflix/conductor/annotationsprocessor/protogen/types/GenericType.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/annotations-processor/src/main/java/com/netflix/conductor/annotationsprocessor/protogen/types/ListType.java b/annotations-processor/src/main/java/com/netflix/conductor/annotationsprocessor/protogen/types/ListType.java index 921594391..50bbf1c7e 100644 --- a/annotations-processor/src/main/java/com/netflix/conductor/annotationsprocessor/protogen/types/ListType.java +++ b/annotations-processor/src/main/java/com/netflix/conductor/annotationsprocessor/protogen/types/ListType.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/annotations-processor/src/main/java/com/netflix/conductor/annotationsprocessor/protogen/types/MapType.java b/annotations-processor/src/main/java/com/netflix/conductor/annotationsprocessor/protogen/types/MapType.java index fe642fdec..bdcb5bfe0 100644 --- a/annotations-processor/src/main/java/com/netflix/conductor/annotationsprocessor/protogen/types/MapType.java +++ b/annotations-processor/src/main/java/com/netflix/conductor/annotationsprocessor/protogen/types/MapType.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/annotations-processor/src/main/java/com/netflix/conductor/annotationsprocessor/protogen/types/MessageType.java b/annotations-processor/src/main/java/com/netflix/conductor/annotationsprocessor/protogen/types/MessageType.java index d57228773..724817af8 100644 --- a/annotations-processor/src/main/java/com/netflix/conductor/annotationsprocessor/protogen/types/MessageType.java +++ b/annotations-processor/src/main/java/com/netflix/conductor/annotationsprocessor/protogen/types/MessageType.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/annotations-processor/src/main/java/com/netflix/conductor/annotationsprocessor/protogen/types/ScalarType.java b/annotations-processor/src/main/java/com/netflix/conductor/annotationsprocessor/protogen/types/ScalarType.java index c6958bdd9..afefc788e 100644 --- a/annotations-processor/src/main/java/com/netflix/conductor/annotationsprocessor/protogen/types/ScalarType.java +++ b/annotations-processor/src/main/java/com/netflix/conductor/annotationsprocessor/protogen/types/ScalarType.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/annotations-processor/src/main/java/com/netflix/conductor/annotationsprocessor/protogen/types/TypeMapper.java b/annotations-processor/src/main/java/com/netflix/conductor/annotationsprocessor/protogen/types/TypeMapper.java index 2363ed365..7e997098f 100644 --- a/annotations-processor/src/main/java/com/netflix/conductor/annotationsprocessor/protogen/types/TypeMapper.java +++ b/annotations-processor/src/main/java/com/netflix/conductor/annotationsprocessor/protogen/types/TypeMapper.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/annotations-processor/src/main/java/com/netflix/conductor/annotationsprocessor/protogen/types/WrappedType.java b/annotations-processor/src/main/java/com/netflix/conductor/annotationsprocessor/protogen/types/WrappedType.java index c6d04e172..409e47dfa 100644 --- a/annotations-processor/src/main/java/com/netflix/conductor/annotationsprocessor/protogen/types/WrappedType.java +++ b/annotations-processor/src/main/java/com/netflix/conductor/annotationsprocessor/protogen/types/WrappedType.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/annotations-processor/src/test/java/com/netflix/conductor/annotationsprocessor/protogen/ProtoGenTest.java b/annotations-processor/src/test/java/com/netflix/conductor/annotationsprocessor/protogen/ProtoGenTest.java index 0fe7a243b..09f637215 100644 --- a/annotations-processor/src/test/java/com/netflix/conductor/annotationsprocessor/protogen/ProtoGenTest.java +++ b/annotations-processor/src/test/java/com/netflix/conductor/annotationsprocessor/protogen/ProtoGenTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/annotations/README.md b/annotations/README.md index aa9ae9fc6..0553d1295 100644 --- a/annotations/README.md +++ b/annotations/README.md @@ -1,4 +1,5 @@ # Annotations +Used for Conductor to convert Java POJs to protobuf files. - `protogen` Annotations - Original Author: Vicent MartĂ­ - https://github.com/vmg diff --git a/annotations/dependencies.lock b/annotations/dependencies.lock deleted file mode 100644 index 2e6c00bb1..000000000 --- a/annotations/dependencies.lock +++ /dev/null @@ -1,249 +0,0 @@ -{ - "annotationProcessor": { - "org.springframework.boot:spring-boot-configuration-processor": { - "locked": "2.7.16" - } - }, - "compileClasspath": { - "com.fasterxml.jackson.core:jackson-annotations": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.core:jackson-core": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.core:jackson-databind": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.dataformat:jackson-dataformat-cbor": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.dataformat:jackson-dataformat-smile": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.dataformat:jackson-dataformat-yaml": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.datatype:jackson-datatype-jdk8": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.datatype:jackson-datatype-joda": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.datatype:jackson-datatype-jsr310": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.module:jackson-module-afterburner": { - "locked": "2.15.0" - }, - "org.apache.logging.log4j:log4j-api": { - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-core": { - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-jul": { - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-slf4j-impl": { - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-web": { - "locked": "2.17.2" - }, - "org.yaml:snakeyaml": { - "locked": "2.0" - } - }, - "runtimeClasspath": { - "com.fasterxml.jackson.core:jackson-annotations": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.core:jackson-core": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.core:jackson-databind": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.dataformat:jackson-dataformat-cbor": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.dataformat:jackson-dataformat-smile": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.dataformat:jackson-dataformat-yaml": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.datatype:jackson-datatype-jdk8": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.datatype:jackson-datatype-joda": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.datatype:jackson-datatype-jsr310": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.module:jackson-module-afterburner": { - "locked": "2.15.0" - }, - "org.apache.logging.log4j:log4j-api": { - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-core": { - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-jul": { - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-slf4j-impl": { - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-web": { - "locked": "2.17.2" - }, - "org.yaml:snakeyaml": { - "locked": "2.0" - } - }, - "testCompileClasspath": { - "com.fasterxml.jackson.core:jackson-annotations": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.core:jackson-core": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.core:jackson-databind": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.dataformat:jackson-dataformat-cbor": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.dataformat:jackson-dataformat-smile": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.dataformat:jackson-dataformat-yaml": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.datatype:jackson-datatype-jdk8": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.datatype:jackson-datatype-joda": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.datatype:jackson-datatype-jsr310": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.module:jackson-module-afterburner": { - "locked": "2.15.0" - }, - "junit:junit": { - "locked": "4.13.2" - }, - "net.java.dev.jna:jna": { - "locked": "5.13.0" - }, - "org.apache.logging.log4j:log4j-api": { - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-core": { - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-jul": { - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-slf4j-impl": { - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-web": { - "locked": "2.17.2" - }, - "org.junit.vintage:junit-vintage-engine": { - "locked": "5.8.2" - }, - "org.springframework.boot:spring-boot-starter-log4j2": { - "locked": "2.7.16" - }, - "org.springframework.boot:spring-boot-starter-test": { - "locked": "2.7.16" - }, - "org.yaml:snakeyaml": { - "locked": "2.0" - } - }, - "testRuntimeClasspath": { - "com.fasterxml.jackson.core:jackson-annotations": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.core:jackson-core": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.core:jackson-databind": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.dataformat:jackson-dataformat-cbor": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.dataformat:jackson-dataformat-smile": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.dataformat:jackson-dataformat-yaml": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.datatype:jackson-datatype-jdk8": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.datatype:jackson-datatype-joda": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.datatype:jackson-datatype-jsr310": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.module:jackson-module-afterburner": { - "locked": "2.15.0" - }, - "junit:junit": { - "locked": "4.13.2" - }, - "net.java.dev.jna:jna": { - "locked": "5.13.0" - }, - "org.apache.logging.log4j:log4j-api": { - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-core": { - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-jul": { - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-slf4j-impl": { - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-web": { - "locked": "2.17.2" - }, - "org.junit.vintage:junit-vintage-engine": { - "locked": "5.8.2" - }, - "org.springframework.boot:spring-boot-starter-log4j2": { - "locked": "2.7.16" - }, - "org.springframework.boot:spring-boot-starter-test": { - "locked": "2.7.16" - }, - "org.yaml:snakeyaml": { - "locked": "2.0" - } - } -} \ No newline at end of file diff --git a/annotations/src/main/java/com/netflix/conductor/annotations/protogen/ProtoEnum.java b/annotations/src/main/java/com/netflix/conductor/annotations/protogen/ProtoEnum.java index 1514a3ed8..c07e679f7 100644 --- a/annotations/src/main/java/com/netflix/conductor/annotations/protogen/ProtoEnum.java +++ b/annotations/src/main/java/com/netflix/conductor/annotations/protogen/ProtoEnum.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/annotations/src/main/java/com/netflix/conductor/annotations/protogen/ProtoField.java b/annotations/src/main/java/com/netflix/conductor/annotations/protogen/ProtoField.java index 25ab478c8..a61bb5ea1 100644 --- a/annotations/src/main/java/com/netflix/conductor/annotations/protogen/ProtoField.java +++ b/annotations/src/main/java/com/netflix/conductor/annotations/protogen/ProtoField.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/annotations/src/main/java/com/netflix/conductor/annotations/protogen/ProtoMessage.java b/annotations/src/main/java/com/netflix/conductor/annotations/protogen/ProtoMessage.java index d66e4aa43..45fa884f9 100644 --- a/annotations/src/main/java/com/netflix/conductor/annotations/protogen/ProtoMessage.java +++ b/annotations/src/main/java/com/netflix/conductor/annotations/protogen/ProtoMessage.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/awss3-storage/README.md b/awss3-storage/README.md index e69de29bb..9672dd01f 100644 --- a/awss3-storage/README.md +++ b/awss3-storage/README.md @@ -0,0 +1,4 @@ +# S3 external storage support +Used by Conductor to support external payload into S3 blob. + +See [https://docs.conductor-oss.org/documentation/advanced/externalpayloadstorage.html](https://docs.conductor-oss.org/documentation/advanced/externalpayloadstorage.html) for more details diff --git a/awss3-storage/build.gradle b/awss3-storage/build.gradle index adda2bb42..57e9d4fc3 100644 --- a/awss3-storage/build.gradle +++ b/awss3-storage/build.gradle @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2023 Conductor authors *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/awss3-storage/dependencies.lock b/awss3-storage/dependencies.lock deleted file mode 100644 index 311ecc794..000000000 --- a/awss3-storage/dependencies.lock +++ /dev/null @@ -1,632 +0,0 @@ -{ - "annotationProcessor": { - "org.springframework.boot:spring-boot-configuration-processor": { - "locked": "2.7.16" - } - }, - "compileClasspath": { - "com.amazonaws:aws-java-sdk-s3": { - "locked": "1.12.535" - }, - "com.fasterxml.jackson.core:jackson-annotations": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.core:jackson-core": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.core:jackson-databind": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.dataformat:jackson-dataformat-cbor": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.dataformat:jackson-dataformat-smile": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.dataformat:jackson-dataformat-yaml": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.datatype:jackson-datatype-jdk8": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.datatype:jackson-datatype-joda": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.datatype:jackson-datatype-jsr310": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.module:jackson-module-afterburner": { - "locked": "2.15.0" - }, - "com.netflix.conductor:conductor-common": { - "project": true - }, - "com.netflix.conductor:conductor-core": { - "project": true - }, - "org.apache.commons:commons-lang3": { - "locked": "3.12.0" - }, - "org.apache.logging.log4j:log4j-api": { - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-core": { - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-jul": { - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-slf4j-impl": { - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-web": { - "locked": "2.17.2" - }, - "org.springframework.boot:spring-boot-starter": { - "locked": "2.7.16" - }, - "org.yaml:snakeyaml": { - "locked": "2.0" - } - }, - "runtimeClasspath": { - "com.amazonaws:aws-java-sdk-s3": { - "locked": "1.12.535" - }, - "com.fasterxml.jackson.core:jackson-annotations": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.core:jackson-core": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.core:jackson-databind": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.dataformat:jackson-dataformat-cbor": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.dataformat:jackson-dataformat-smile": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.dataformat:jackson-dataformat-yaml": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.datatype:jackson-datatype-jdk8": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.datatype:jackson-datatype-joda": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.datatype:jackson-datatype-jsr310": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.module:jackson-module-afterburner": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "2.15.0" - }, - "com.github.ben-manes.caffeine:caffeine": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-core" - ], - "locked": "2.9.3" - }, - "com.google.protobuf:protobuf-java": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "3.24.3" - }, - "com.jayway.jsonpath:json-path": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-core" - ], - "locked": "2.7.0" - }, - "com.netflix.conductor:conductor-annotations": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-common" - ], - "project": true - }, - "com.netflix.conductor:conductor-common": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-core" - ], - "project": true - }, - "com.netflix.conductor:conductor-core": { - "project": true - }, - "com.netflix.spectator:spectator-api": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-core" - ], - "locked": "0.122.0" - }, - "com.spotify:completable-futures": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-core" - ], - "locked": "0.3.3" - }, - "commons-io:commons-io": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-core" - ], - "locked": "2.7" - }, - "io.reactivex:rxjava": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-core" - ], - "locked": "1.3.8" - }, - "jakarta.activation:jakarta.activation-api": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-core" - ], - "locked": "1.2.2" - }, - "jakarta.xml.bind:jakarta.xml.bind-api": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-core" - ], - "locked": "2.3.3" - }, - "org.apache.bval:bval-jsr": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "2.0.6" - }, - "org.apache.commons:commons-lang3": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "3.12.0" - }, - "org.apache.logging.log4j:log4j-api": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-core": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-jul": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-slf4j-impl": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-web": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "2.17.2" - }, - "org.openjdk.nashorn:nashorn-core": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-core" - ], - "locked": "15.4" - }, - "org.yaml:snakeyaml": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "2.0" - } - }, - "testCompileClasspath": { - "com.amazonaws:aws-java-sdk-s3": { - "locked": "1.12.535" - }, - "com.fasterxml.jackson.core:jackson-annotations": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.core:jackson-core": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.core:jackson-databind": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.dataformat:jackson-dataformat-cbor": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.dataformat:jackson-dataformat-smile": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.dataformat:jackson-dataformat-yaml": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.datatype:jackson-datatype-jdk8": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.datatype:jackson-datatype-joda": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.datatype:jackson-datatype-jsr310": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.module:jackson-module-afterburner": { - "locked": "2.15.0" - }, - "com.netflix.conductor:conductor-common": { - "project": true - }, - "com.netflix.conductor:conductor-core": { - "project": true - }, - "junit:junit": { - "locked": "4.13.2" - }, - "net.java.dev.jna:jna": { - "locked": "5.13.0" - }, - "org.apache.commons:commons-lang3": { - "locked": "3.12.0" - }, - "org.apache.logging.log4j:log4j-api": { - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-core": { - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-jul": { - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-slf4j-impl": { - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-web": { - "locked": "2.17.2" - }, - "org.junit.vintage:junit-vintage-engine": { - "locked": "5.8.2" - }, - "org.springframework.boot:spring-boot-starter-log4j2": { - "locked": "2.7.16" - }, - "org.springframework.boot:spring-boot-starter-test": { - "locked": "2.7.16" - }, - "org.yaml:snakeyaml": { - "locked": "2.0" - } - }, - "testRuntimeClasspath": { - "com.amazonaws:aws-java-sdk-s3": { - "locked": "1.12.535" - }, - "com.fasterxml.jackson.core:jackson-annotations": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.core:jackson-core": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.core:jackson-databind": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.dataformat:jackson-dataformat-cbor": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.dataformat:jackson-dataformat-smile": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.dataformat:jackson-dataformat-yaml": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.datatype:jackson-datatype-jdk8": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.datatype:jackson-datatype-joda": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.datatype:jackson-datatype-jsr310": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.module:jackson-module-afterburner": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "2.15.0" - }, - "com.github.ben-manes.caffeine:caffeine": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-core" - ], - "locked": "2.9.3" - }, - "com.google.protobuf:protobuf-java": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "3.24.3" - }, - "com.jayway.jsonpath:json-path": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-core" - ], - "locked": "2.7.0" - }, - "com.netflix.conductor:conductor-annotations": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-common" - ], - "project": true - }, - "com.netflix.conductor:conductor-common": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-core" - ], - "project": true - }, - "com.netflix.conductor:conductor-core": { - "project": true - }, - "com.netflix.spectator:spectator-api": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-core" - ], - "locked": "0.122.0" - }, - "com.spotify:completable-futures": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-core" - ], - "locked": "0.3.3" - }, - "commons-io:commons-io": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-core" - ], - "locked": "2.7" - }, - "io.reactivex:rxjava": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-core" - ], - "locked": "1.3.8" - }, - "jakarta.activation:jakarta.activation-api": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-core" - ], - "locked": "1.2.2" - }, - "jakarta.xml.bind:jakarta.xml.bind-api": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-core" - ], - "locked": "2.3.3" - }, - "junit:junit": { - "locked": "4.13.2" - }, - "net.java.dev.jna:jna": { - "locked": "5.13.0" - }, - "org.apache.bval:bval-jsr": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "2.0.6" - }, - "org.apache.commons:commons-lang3": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "3.12.0" - }, - "org.apache.logging.log4j:log4j-api": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-core": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-jul": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-slf4j-impl": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-web": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "2.17.2" - }, - "org.junit.vintage:junit-vintage-engine": { - "locked": "5.8.2" - }, - "org.openjdk.nashorn:nashorn-core": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-core" - ], - "locked": "15.4" - }, - "org.springframework.boot:spring-boot-starter-log4j2": { - "locked": "2.7.16" - }, - "org.springframework.boot:spring-boot-starter-test": { - "locked": "2.7.16" - }, - "org.yaml:snakeyaml": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "2.0" - } - } -} \ No newline at end of file diff --git a/awss3-storage/src/main/java/com/netflix/conductor/s3/config/S3Configuration.java b/awss3-storage/src/main/java/com/netflix/conductor/s3/config/S3Configuration.java index 5b8e6b3dc..b14d79395 100644 --- a/awss3-storage/src/main/java/com/netflix/conductor/s3/config/S3Configuration.java +++ b/awss3-storage/src/main/java/com/netflix/conductor/s3/config/S3Configuration.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/awss3-storage/src/main/java/com/netflix/conductor/s3/config/S3Properties.java b/awss3-storage/src/main/java/com/netflix/conductor/s3/config/S3Properties.java index 94a515f72..9c41b4a10 100644 --- a/awss3-storage/src/main/java/com/netflix/conductor/s3/config/S3Properties.java +++ b/awss3-storage/src/main/java/com/netflix/conductor/s3/config/S3Properties.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/awss3-storage/src/main/java/com/netflix/conductor/s3/storage/S3PayloadStorage.java b/awss3-storage/src/main/java/com/netflix/conductor/s3/storage/S3PayloadStorage.java index 838ab4088..19ac68d27 100644 --- a/awss3-storage/src/main/java/com/netflix/conductor/s3/storage/S3PayloadStorage.java +++ b/awss3-storage/src/main/java/com/netflix/conductor/s3/storage/S3PayloadStorage.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/awssqs-event-queue/dependencies.lock b/awssqs-event-queue/dependencies.lock deleted file mode 100644 index 3fe9d6ca9..000000000 --- a/awssqs-event-queue/dependencies.lock +++ /dev/null @@ -1,656 +0,0 @@ -{ - "annotationProcessor": { - "org.springframework.boot:spring-boot-configuration-processor": { - "locked": "2.7.16" - } - }, - "compileClasspath": { - "com.amazonaws:aws-java-sdk-sqs": { - "locked": "1.12.535" - }, - "com.fasterxml.jackson.core:jackson-annotations": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.core:jackson-core": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.core:jackson-databind": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.dataformat:jackson-dataformat-cbor": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.dataformat:jackson-dataformat-smile": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.dataformat:jackson-dataformat-yaml": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.datatype:jackson-datatype-jdk8": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.datatype:jackson-datatype-joda": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.datatype:jackson-datatype-jsr310": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.module:jackson-module-afterburner": { - "locked": "2.15.0" - }, - "com.google.guava:guava": { - "locked": "32.1.2-jre" - }, - "com.netflix.conductor:conductor-common": { - "project": true - }, - "com.netflix.conductor:conductor-core": { - "project": true - }, - "io.reactivex:rxjava": { - "locked": "1.2.2" - }, - "org.apache.commons:commons-lang3": { - "locked": "3.12.0" - }, - "org.apache.logging.log4j:log4j-api": { - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-core": { - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-jul": { - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-slf4j-impl": { - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-web": { - "locked": "2.17.2" - }, - "org.springframework.boot:spring-boot-starter": { - "locked": "2.7.16" - }, - "org.yaml:snakeyaml": { - "locked": "2.0" - } - }, - "runtimeClasspath": { - "com.amazonaws:aws-java-sdk-sqs": { - "locked": "1.12.535" - }, - "com.fasterxml.jackson.core:jackson-annotations": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.core:jackson-core": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.core:jackson-databind": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.dataformat:jackson-dataformat-cbor": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.dataformat:jackson-dataformat-smile": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.dataformat:jackson-dataformat-yaml": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.datatype:jackson-datatype-jdk8": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.datatype:jackson-datatype-joda": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.datatype:jackson-datatype-jsr310": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.module:jackson-module-afterburner": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "2.15.0" - }, - "com.github.ben-manes.caffeine:caffeine": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-core" - ], - "locked": "2.9.3" - }, - "com.google.guava:guava": { - "locked": "32.1.2-jre" - }, - "com.google.protobuf:protobuf-java": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "3.24.3" - }, - "com.jayway.jsonpath:json-path": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-core" - ], - "locked": "2.7.0" - }, - "com.netflix.conductor:conductor-annotations": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-common" - ], - "project": true - }, - "com.netflix.conductor:conductor-common": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-core" - ], - "project": true - }, - "com.netflix.conductor:conductor-core": { - "project": true - }, - "com.netflix.spectator:spectator-api": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-core" - ], - "locked": "0.122.0" - }, - "com.spotify:completable-futures": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-core" - ], - "locked": "0.3.3" - }, - "commons-io:commons-io": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-core" - ], - "locked": "2.7" - }, - "io.reactivex:rxjava": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-core" - ], - "locked": "1.2.2" - }, - "jakarta.activation:jakarta.activation-api": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-core" - ], - "locked": "1.2.2" - }, - "jakarta.xml.bind:jakarta.xml.bind-api": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-core" - ], - "locked": "2.3.3" - }, - "org.apache.bval:bval-jsr": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "2.0.6" - }, - "org.apache.commons:commons-lang3": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "3.12.0" - }, - "org.apache.logging.log4j:log4j-api": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-core": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-jul": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-slf4j-impl": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-web": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "2.17.2" - }, - "org.openjdk.nashorn:nashorn-core": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-core" - ], - "locked": "15.4" - }, - "org.yaml:snakeyaml": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "2.0" - } - }, - "testCompileClasspath": { - "com.amazonaws:aws-java-sdk-sqs": { - "locked": "1.12.535" - }, - "com.fasterxml.jackson.core:jackson-annotations": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.core:jackson-core": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.core:jackson-databind": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.dataformat:jackson-dataformat-cbor": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.dataformat:jackson-dataformat-smile": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.dataformat:jackson-dataformat-yaml": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.datatype:jackson-datatype-jdk8": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.datatype:jackson-datatype-joda": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.datatype:jackson-datatype-jsr310": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.module:jackson-module-afterburner": { - "locked": "2.15.0" - }, - "com.google.guava:guava": { - "locked": "32.1.2-jre" - }, - "com.netflix.conductor:conductor-common": { - "project": true - }, - "com.netflix.conductor:conductor-core": { - "project": true - }, - "io.reactivex:rxjava": { - "locked": "1.2.2" - }, - "junit:junit": { - "locked": "4.13.2" - }, - "net.java.dev.jna:jna": { - "locked": "5.13.0" - }, - "org.apache.commons:commons-lang3": { - "locked": "3.12.0" - }, - "org.apache.logging.log4j:log4j-api": { - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-core": { - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-jul": { - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-slf4j-impl": { - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-web": { - "locked": "2.17.2" - }, - "org.junit.vintage:junit-vintage-engine": { - "locked": "5.8.2" - }, - "org.springframework.boot:spring-boot-starter": { - "locked": "2.7.16" - }, - "org.springframework.boot:spring-boot-starter-log4j2": { - "locked": "2.7.16" - }, - "org.springframework.boot:spring-boot-starter-test": { - "locked": "2.7.16" - }, - "org.yaml:snakeyaml": { - "locked": "2.0" - } - }, - "testRuntimeClasspath": { - "com.amazonaws:aws-java-sdk-sqs": { - "locked": "1.12.535" - }, - "com.fasterxml.jackson.core:jackson-annotations": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.core:jackson-core": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.core:jackson-databind": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.dataformat:jackson-dataformat-cbor": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.dataformat:jackson-dataformat-smile": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.dataformat:jackson-dataformat-yaml": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.datatype:jackson-datatype-jdk8": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.datatype:jackson-datatype-joda": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.datatype:jackson-datatype-jsr310": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.module:jackson-module-afterburner": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "2.15.0" - }, - "com.github.ben-manes.caffeine:caffeine": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-core" - ], - "locked": "2.9.3" - }, - "com.google.guava:guava": { - "locked": "32.1.2-jre" - }, - "com.google.protobuf:protobuf-java": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "3.24.3" - }, - "com.jayway.jsonpath:json-path": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-core" - ], - "locked": "2.7.0" - }, - "com.netflix.conductor:conductor-annotations": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-common" - ], - "project": true - }, - "com.netflix.conductor:conductor-common": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-core" - ], - "project": true - }, - "com.netflix.conductor:conductor-core": { - "project": true - }, - "com.netflix.spectator:spectator-api": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-core" - ], - "locked": "0.122.0" - }, - "com.spotify:completable-futures": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-core" - ], - "locked": "0.3.3" - }, - "commons-io:commons-io": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-core" - ], - "locked": "2.7" - }, - "io.reactivex:rxjava": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-core" - ], - "locked": "1.2.2" - }, - "jakarta.activation:jakarta.activation-api": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-core" - ], - "locked": "1.2.2" - }, - "jakarta.xml.bind:jakarta.xml.bind-api": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-core" - ], - "locked": "2.3.3" - }, - "junit:junit": { - "locked": "4.13.2" - }, - "net.java.dev.jna:jna": { - "locked": "5.13.0" - }, - "org.apache.bval:bval-jsr": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "2.0.6" - }, - "org.apache.commons:commons-lang3": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "3.12.0" - }, - "org.apache.logging.log4j:log4j-api": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-core": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-jul": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-slf4j-impl": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-web": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "2.17.2" - }, - "org.junit.vintage:junit-vintage-engine": { - "locked": "5.8.2" - }, - "org.openjdk.nashorn:nashorn-core": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-core" - ], - "locked": "15.4" - }, - "org.springframework.boot:spring-boot-starter": { - "locked": "2.7.16" - }, - "org.springframework.boot:spring-boot-starter-log4j2": { - "locked": "2.7.16" - }, - "org.springframework.boot:spring-boot-starter-test": { - "locked": "2.7.16" - }, - "org.yaml:snakeyaml": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "2.0" - } - } -} \ No newline at end of file diff --git a/awssqs-event-queue/src/main/java/com/netflix/conductor/sqs/config/SQSEventQueueConfiguration.java b/awssqs-event-queue/src/main/java/com/netflix/conductor/sqs/config/SQSEventQueueConfiguration.java index fb3065895..1f4165423 100644 --- a/awssqs-event-queue/src/main/java/com/netflix/conductor/sqs/config/SQSEventQueueConfiguration.java +++ b/awssqs-event-queue/src/main/java/com/netflix/conductor/sqs/config/SQSEventQueueConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/awssqs-event-queue/src/main/java/com/netflix/conductor/sqs/config/SQSEventQueueProperties.java b/awssqs-event-queue/src/main/java/com/netflix/conductor/sqs/config/SQSEventQueueProperties.java index 4bd9eb9ba..fbe40eea9 100644 --- a/awssqs-event-queue/src/main/java/com/netflix/conductor/sqs/config/SQSEventQueueProperties.java +++ b/awssqs-event-queue/src/main/java/com/netflix/conductor/sqs/config/SQSEventQueueProperties.java @@ -1,5 +1,5 @@ /* - * Copyright 2020 Netflix, Inc. + * Copyright 2020 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/awssqs-event-queue/src/main/java/com/netflix/conductor/sqs/config/SQSEventQueueProvider.java b/awssqs-event-queue/src/main/java/com/netflix/conductor/sqs/config/SQSEventQueueProvider.java index 2d0b45e21..425012086 100644 --- a/awssqs-event-queue/src/main/java/com/netflix/conductor/sqs/config/SQSEventQueueProvider.java +++ b/awssqs-event-queue/src/main/java/com/netflix/conductor/sqs/config/SQSEventQueueProvider.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/awssqs-event-queue/src/main/java/com/netflix/conductor/sqs/eventqueue/SQSObservableQueue.java b/awssqs-event-queue/src/main/java/com/netflix/conductor/sqs/eventqueue/SQSObservableQueue.java index 95a1771b7..5f3e4173b 100644 --- a/awssqs-event-queue/src/main/java/com/netflix/conductor/sqs/eventqueue/SQSObservableQueue.java +++ b/awssqs-event-queue/src/main/java/com/netflix/conductor/sqs/eventqueue/SQSObservableQueue.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/awssqs-event-queue/src/test/java/com/netflix/conductor/sqs/eventqueue/DefaultEventQueueProcessorTest.java b/awssqs-event-queue/src/test/java/com/netflix/conductor/sqs/eventqueue/DefaultEventQueueProcessorTest.java index ab7be3118..1607acf44 100644 --- a/awssqs-event-queue/src/test/java/com/netflix/conductor/sqs/eventqueue/DefaultEventQueueProcessorTest.java +++ b/awssqs-event-queue/src/test/java/com/netflix/conductor/sqs/eventqueue/DefaultEventQueueProcessorTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/awssqs-event-queue/src/test/java/com/netflix/conductor/sqs/eventqueue/SQSObservableQueueTest.java b/awssqs-event-queue/src/test/java/com/netflix/conductor/sqs/eventqueue/SQSObservableQueueTest.java index 7c0d69aa5..39acc6f54 100644 --- a/awssqs-event-queue/src/test/java/com/netflix/conductor/sqs/eventqueue/SQSObservableQueueTest.java +++ b/awssqs-event-queue/src/test/java/com/netflix/conductor/sqs/eventqueue/SQSObservableQueueTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/azureblob-storage/README.md b/azureblob-storage/README.md new file mode 100644 index 000000000..e562f1032 --- /dev/null +++ b/azureblob-storage/README.md @@ -0,0 +1,45 @@ +# Azure Blob External Storage Module + +This module use azure blob to store and retrieve workflows/tasks input/output payload that +went over the thresholds defined in properties named `conductor.[workflow|task].[input|output].payload.threshold.kb`. + +**Warning** Azure Java SDK use libs already present inside `conductor` like `jackson` and `netty`. +You may encounter deprecated issues, or conflicts and need to adapt the code if the module is not maintained along with `conductor`. +It has only been tested with **v12.2.0**. + +## Configuration + +### Usage + +Documentation [External Payload Storage]([https://netflix.github.io/conductor/externalpayloadstorage/#azure-blob-storage](https://docs.conductor-oss.org/documentation/advanced/externalpayloadstorage.html)) + +See [https://docs.conductor-oss.org/documentation/advanced/externalpayloadstorage.html]() for more details +### Example + +```properties +conductor.additional.modules=com.netflix.conductor.azureblob.AzureBlobModule +es.set.netty.runtime.available.processors=false + +workflow.external.payload.storage=AZURE_BLOB +workflow.external.payload.storage.azure_blob.connection_string=DefaultEndpointsProtocol=http;AccountName=devstoreaccount1;AccountKey=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==;BlobEndpoint=http://127.0.0.1:10000/devstoreaccount1;EndpointSuffix=localhost +workflow.external.payload.storage.azure_blob.signedurlexpirationseconds=360 +``` + +## Testing + +You can use [Azurite](https://github.com/Azure/Azurite) to simulate an Azure Storage. + +### Troubleshoots + +* When using **es5 persistance** you will receive an `java.lang.IllegalStateException` because the Netty lib will call `setAvailableProcessors` two times. To resolve this issue you need to set the following system property + +``` +es.set.netty.runtime.available.processors=false +``` + +If you want to change the default HTTP client of azure sdk, you can use `okhttp` instead of `netty`. +For that you need to add the following [dependency](https://github.com/Azure/azure-sdk-for-java/tree/master/sdk/storage/azure-storage-blob#default-http-client). + +``` +com.azure:azure-core-http-okhttp:${compatible version} +``` diff --git a/azureblob-storage/build.gradle b/azureblob-storage/build.gradle new file mode 100644 index 000000000..8e4b4627b --- /dev/null +++ b/azureblob-storage/build.gradle @@ -0,0 +1,8 @@ +dependencies { + compileOnly 'org.springframework.boot:spring-boot-starter' + implementation project(':conductor-common') + implementation project(':conductor-core') + + implementation "com.azure:azure-storage-blob:${revAzureStorageBlobSdk}" + implementation "org.apache.commons:commons-lang3" +} diff --git a/azureblob-storage/src/main/java/com/netflix/conductor/azureblob/config/AzureBlobConfiguration.java b/azureblob-storage/src/main/java/com/netflix/conductor/azureblob/config/AzureBlobConfiguration.java new file mode 100644 index 000000000..49c0a2f68 --- /dev/null +++ b/azureblob-storage/src/main/java/com/netflix/conductor/azureblob/config/AzureBlobConfiguration.java @@ -0,0 +1,34 @@ +/* + * Copyright 2023 Conductor Authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package com.netflix.conductor.azureblob.config; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import com.netflix.conductor.azureblob.storage.AzureBlobPayloadStorage; +import com.netflix.conductor.common.utils.ExternalPayloadStorage; +import com.netflix.conductor.core.utils.IDGenerator; + +@Configuration(proxyBeanMethods = false) +@EnableConfigurationProperties(AzureBlobProperties.class) +@ConditionalOnProperty(name = "conductor.external-payload-storage.type", havingValue = "azureblob") +public class AzureBlobConfiguration { + + @Bean + public ExternalPayloadStorage azureBlobExternalPayloadStorage( + IDGenerator idGenerator, AzureBlobProperties properties) { + return new AzureBlobPayloadStorage(idGenerator, properties); + } +} diff --git a/azureblob-storage/src/main/java/com/netflix/conductor/azureblob/config/AzureBlobProperties.java b/azureblob-storage/src/main/java/com/netflix/conductor/azureblob/config/AzureBlobProperties.java new file mode 100644 index 000000000..3932bd677 --- /dev/null +++ b/azureblob-storage/src/main/java/com/netflix/conductor/azureblob/config/AzureBlobProperties.java @@ -0,0 +1,123 @@ +/* + * Copyright 2023 Conductor Authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package com.netflix.conductor.azureblob.config; + +import java.time.Duration; +import java.time.temporal.ChronoUnit; + +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.boot.convert.DurationUnit; + +@ConfigurationProperties("conductor.external-payload-storage.azureblob") +public class AzureBlobProperties { + + /** The connection string to be used to connect to Azure Blob storage */ + private String connectionString = null; + + /** The name of the container where the payloads will be stored */ + private String containerName = "conductor-payloads"; + + /** The endpoint to be used to connect to Azure Blob storage */ + private String endpoint = null; + + /** The sas token to be used for authenticating requests */ + private String sasToken = null; + + /** The time for which the shared access signature is valid */ + @DurationUnit(ChronoUnit.SECONDS) + private Duration signedUrlExpirationDuration = Duration.ofSeconds(5); + + /** The path at which the workflow inputs will be stored */ + private String workflowInputPath = "workflow/input/"; + + /** The path at which the workflow outputs will be stored */ + private String workflowOutputPath = "workflow/output/"; + + /** The path at which the task inputs will be stored */ + private String taskInputPath = "task/input/"; + + /** The path at which the task outputs will be stored */ + private String taskOutputPath = "task/output/"; + + public String getConnectionString() { + return connectionString; + } + + public void setConnectionString(String connectionString) { + this.connectionString = connectionString; + } + + public String getContainerName() { + return containerName; + } + + public void setContainerName(String containerName) { + this.containerName = containerName; + } + + public String getEndpoint() { + return endpoint; + } + + public void setEndpoint(String endpoint) { + this.endpoint = endpoint; + } + + public String getSasToken() { + return sasToken; + } + + public void setSasToken(String sasToken) { + this.sasToken = sasToken; + } + + public Duration getSignedUrlExpirationDuration() { + return signedUrlExpirationDuration; + } + + public void setSignedUrlExpirationDuration(Duration signedUrlExpirationDuration) { + this.signedUrlExpirationDuration = signedUrlExpirationDuration; + } + + public String getWorkflowInputPath() { + return workflowInputPath; + } + + public void setWorkflowInputPath(String workflowInputPath) { + this.workflowInputPath = workflowInputPath; + } + + public String getWorkflowOutputPath() { + return workflowOutputPath; + } + + public void setWorkflowOutputPath(String workflowOutputPath) { + this.workflowOutputPath = workflowOutputPath; + } + + public String getTaskInputPath() { + return taskInputPath; + } + + public void setTaskInputPath(String taskInputPath) { + this.taskInputPath = taskInputPath; + } + + public String getTaskOutputPath() { + return taskOutputPath; + } + + public void setTaskOutputPath(String taskOutputPath) { + this.taskOutputPath = taskOutputPath; + } +} diff --git a/azureblob-storage/src/main/java/com/netflix/conductor/azureblob/storage/AzureBlobPayloadStorage.java b/azureblob-storage/src/main/java/com/netflix/conductor/azureblob/storage/AzureBlobPayloadStorage.java new file mode 100644 index 000000000..6d1ead96d --- /dev/null +++ b/azureblob-storage/src/main/java/com/netflix/conductor/azureblob/storage/AzureBlobPayloadStorage.java @@ -0,0 +1,230 @@ +/* + * Copyright 2023 Conductor Authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package com.netflix.conductor.azureblob.storage; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.InputStream; +import java.io.UncheckedIOException; +import java.time.OffsetDateTime; +import java.time.ZoneOffset; + +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.netflix.conductor.azureblob.config.AzureBlobProperties; +import com.netflix.conductor.common.run.ExternalStorageLocation; +import com.netflix.conductor.common.utils.ExternalPayloadStorage; +import com.netflix.conductor.core.exception.NonTransientException; +import com.netflix.conductor.core.utils.IDGenerator; + +import com.azure.core.exception.UnexpectedLengthException; +import com.azure.core.util.Context; +import com.azure.storage.blob.BlobContainerClient; +import com.azure.storage.blob.BlobContainerClientBuilder; +import com.azure.storage.blob.models.BlobHttpHeaders; +import com.azure.storage.blob.models.BlobStorageException; +import com.azure.storage.blob.sas.BlobSasPermission; +import com.azure.storage.blob.sas.BlobServiceSasSignatureValues; +import com.azure.storage.blob.specialized.BlockBlobClient; +import com.azure.storage.common.Utility; +import com.azure.storage.common.implementation.credentials.SasTokenCredential; + +/** + * An implementation of {@link ExternalPayloadStorage} using Azure Blob for storing large JSON + * payload data. + * + * @see Azure Java SDK + */ +public class AzureBlobPayloadStorage implements ExternalPayloadStorage { + + private static final Logger LOGGER = LoggerFactory.getLogger(AzureBlobPayloadStorage.class); + private static final String CONTENT_TYPE = "application/json"; + + private final IDGenerator idGenerator; + private final String workflowInputPath; + private final String workflowOutputPath; + private final String taskInputPath; + private final String taskOutputPath; + + private final BlobContainerClient blobContainerClient; + private final long expirationSec; + private final SasTokenCredential sasTokenCredential; + + public AzureBlobPayloadStorage(IDGenerator idGenerator, AzureBlobProperties properties) { + this.idGenerator = idGenerator; + workflowInputPath = properties.getWorkflowInputPath(); + workflowOutputPath = properties.getWorkflowOutputPath(); + taskInputPath = properties.getTaskInputPath(); + taskOutputPath = properties.getTaskOutputPath(); + expirationSec = properties.getSignedUrlExpirationDuration().getSeconds(); + String connectionString = properties.getConnectionString(); + String containerName = properties.getContainerName(); + String endpoint = properties.getEndpoint(); + String sasToken = properties.getSasToken(); + + BlobContainerClientBuilder blobContainerClientBuilder = new BlobContainerClientBuilder(); + if (connectionString != null) { + blobContainerClientBuilder.connectionString(connectionString); + sasTokenCredential = null; + } else if (endpoint != null) { + blobContainerClientBuilder.endpoint(endpoint); + if (sasToken != null) { + sasTokenCredential = SasTokenCredential.fromSasTokenString(sasToken); + blobContainerClientBuilder.sasToken(sasTokenCredential.getSasToken()); + } else { + sasTokenCredential = null; + } + } else { + String msg = "Missing property for connectionString OR endpoint"; + LOGGER.error(msg); + throw new NonTransientException(msg); + } + blobContainerClient = blobContainerClientBuilder.containerName(containerName).buildClient(); + } + + /** + * @param operation the type of {@link Operation} to be performed + * @param payloadType the {@link PayloadType} that is being accessed + * @return a {@link ExternalStorageLocation} object which contains the pre-signed URL and the + * azure blob name for the json payload + */ + @Override + public ExternalStorageLocation getLocation( + Operation operation, PayloadType payloadType, String path) { + try { + ExternalStorageLocation externalStorageLocation = new ExternalStorageLocation(); + + String objectKey; + if (StringUtils.isNotBlank(path)) { + objectKey = path; + } else { + objectKey = getObjectKey(payloadType); + } + externalStorageLocation.setPath(objectKey); + + BlockBlobClient blockBlobClient = + blobContainerClient.getBlobClient(objectKey).getBlockBlobClient(); + String blobUrl = Utility.urlDecode(blockBlobClient.getBlobUrl()); + + if (sasTokenCredential != null) { + blobUrl = blobUrl + "?" + sasTokenCredential.getSasToken(); + } else { + BlobSasPermission blobSASPermission = new BlobSasPermission(); + if (operation.equals(Operation.READ)) { + blobSASPermission.setReadPermission(true); + } else if (operation.equals(Operation.WRITE)) { + blobSASPermission.setWritePermission(true); + blobSASPermission.setCreatePermission(true); + } + BlobServiceSasSignatureValues blobServiceSasSignatureValues = + new BlobServiceSasSignatureValues( + OffsetDateTime.now(ZoneOffset.UTC).plusSeconds(expirationSec), + blobSASPermission); + blobUrl = + blobUrl + "?" + blockBlobClient.generateSas(blobServiceSasSignatureValues); + } + + externalStorageLocation.setUri(blobUrl); + return externalStorageLocation; + } catch (BlobStorageException e) { + String msg = "Error communicating with Azure"; + LOGGER.error(msg, e); + throw new NonTransientException(msg, e); + } + } + + /** + * Uploads the payload to the given azure blob name. It is expected that the caller retrieves + * the blob name using {@link #getLocation(Operation, PayloadType, String)} before making this + * call. + * + * @param path the name of the blob to be uploaded + * @param payload an {@link InputStream} containing the json payload which is to be uploaded + * @param payloadSize the size of the json payload in bytes + */ + @Override + public void upload(String path, InputStream payload, long payloadSize) { + try { + BlockBlobClient blockBlobClient = + blobContainerClient.getBlobClient(path).getBlockBlobClient(); + BlobHttpHeaders blobHttpHeaders = new BlobHttpHeaders().setContentType(CONTENT_TYPE); + blockBlobClient.uploadWithResponse( + payload, + payloadSize, + blobHttpHeaders, + null, + null, + null, + null, + null, + Context.NONE); + } catch (BlobStorageException | UncheckedIOException | UnexpectedLengthException e) { + String msg = "Error communicating with Azure"; + LOGGER.error(msg, e); + throw new NonTransientException(msg, e); + } + } + + /** + * Downloads the payload stored in an azure blob. + * + * @param path the path of the blob + * @return an input stream containing the contents of the object Caller is expected to close the + * input stream. + */ + @Override + public InputStream download(String path) { + try { + BlockBlobClient blockBlobClient = + blobContainerClient.getBlobClient(path).getBlockBlobClient(); + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + // Avoid another call to the api to get the blob size + // ByteArrayOutputStream outputStream = new + // ByteArrayOutputStream(blockBlobClient.getProperties().value().blobSize()); + blockBlobClient.download(outputStream); + return new ByteArrayInputStream(outputStream.toByteArray()); + } catch (BlobStorageException | UncheckedIOException | NullPointerException e) { + String msg = "Error communicating with Azure"; + LOGGER.error(msg, e); + throw new NonTransientException(msg, e); + } + } + + /** + * Build path on external storage. Copied from S3PayloadStorage. + * + * @param payloadType the {@link PayloadType} which will determine the base path of the object + * @return External Storage path + */ + private String getObjectKey(PayloadType payloadType) { + StringBuilder stringBuilder = new StringBuilder(); + switch (payloadType) { + case WORKFLOW_INPUT: + stringBuilder.append(workflowInputPath); + break; + case WORKFLOW_OUTPUT: + stringBuilder.append(workflowOutputPath); + break; + case TASK_INPUT: + stringBuilder.append(taskInputPath); + break; + case TASK_OUTPUT: + stringBuilder.append(taskOutputPath); + break; + } + stringBuilder.append(idGenerator.generate()).append(".json"); + return stringBuilder.toString(); + } +} diff --git a/azureblob-storage/src/test/java/com/netflix/conductor/azureblob/storage/AzureBlobPayloadStorageTest.java b/azureblob-storage/src/test/java/com/netflix/conductor/azureblob/storage/AzureBlobPayloadStorageTest.java new file mode 100644 index 000000000..2935f609d --- /dev/null +++ b/azureblob-storage/src/test/java/com/netflix/conductor/azureblob/storage/AzureBlobPayloadStorageTest.java @@ -0,0 +1,158 @@ +/* + * Copyright 2023 Conductor Authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package com.netflix.conductor.azureblob.storage; + +import java.time.Duration; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +import com.netflix.conductor.azureblob.config.AzureBlobProperties; +import com.netflix.conductor.common.run.ExternalStorageLocation; +import com.netflix.conductor.common.utils.ExternalPayloadStorage; +import com.netflix.conductor.core.exception.NonTransientException; +import com.netflix.conductor.core.utils.IDGenerator; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class AzureBlobPayloadStorageTest { + + private AzureBlobProperties properties; + + private IDGenerator idGenerator; + + @Before + public void setUp() { + properties = mock(AzureBlobProperties.class); + idGenerator = new IDGenerator(); + when(properties.getConnectionString()).thenReturn(null); + when(properties.getContainerName()).thenReturn("conductor-payloads"); + when(properties.getEndpoint()).thenReturn(null); + when(properties.getSasToken()).thenReturn(null); + when(properties.getSignedUrlExpirationDuration()).thenReturn(Duration.ofSeconds(5)); + when(properties.getWorkflowInputPath()).thenReturn("workflow/input/"); + when(properties.getWorkflowOutputPath()).thenReturn("workflow/output/"); + when(properties.getTaskInputPath()).thenReturn("task/input"); + when(properties.getTaskOutputPath()).thenReturn("task/output/"); + } + + /** Dummy credentials Azure SDK doesn't work with Azurite since it cleans parameters */ + private final String azuriteConnectionString = + "DefaultEndpointsProtocol=http;AccountName=devstoreaccount1;AccountKey=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==;BlobEndpoint=http://127.0.0.1:10000/devstoreaccount1;EndpointSuffix=localhost"; + + @Rule public ExpectedException expectedException = ExpectedException.none(); + + @Test + public void testNoStorageAccount() { + expectedException.expect(NonTransientException.class); + new AzureBlobPayloadStorage(idGenerator, properties); + } + + @Test + public void testUseConnectionString() { + when(properties.getConnectionString()).thenReturn(azuriteConnectionString); + new AzureBlobPayloadStorage(idGenerator, properties); + } + + @Test + public void testUseEndpoint() { + String azuriteEndpoint = "http://127.0.0.1:10000/"; + when(properties.getEndpoint()).thenReturn(azuriteEndpoint); + new AzureBlobPayloadStorage(idGenerator, properties); + } + + @Test + public void testGetLocationFixedPath() { + when(properties.getConnectionString()).thenReturn(azuriteConnectionString); + AzureBlobPayloadStorage azureBlobPayloadStorage = + new AzureBlobPayloadStorage(idGenerator, properties); + String path = "somewhere"; + ExternalStorageLocation externalStorageLocation = + azureBlobPayloadStorage.getLocation( + ExternalPayloadStorage.Operation.READ, + ExternalPayloadStorage.PayloadType.WORKFLOW_INPUT, + path); + assertNotNull(externalStorageLocation); + assertEquals(path, externalStorageLocation.getPath()); + assertNotNull(externalStorageLocation.getUri()); + } + + private void testGetLocation( + AzureBlobPayloadStorage azureBlobPayloadStorage, + ExternalPayloadStorage.Operation operation, + ExternalPayloadStorage.PayloadType payloadType, + String expectedPath) { + ExternalStorageLocation externalStorageLocation = + azureBlobPayloadStorage.getLocation(operation, payloadType, null); + assertNotNull(externalStorageLocation); + assertNotNull(externalStorageLocation.getPath()); + assertTrue(externalStorageLocation.getPath().startsWith(expectedPath)); + assertNotNull(externalStorageLocation.getUri()); + assertTrue(externalStorageLocation.getUri().contains(expectedPath)); + } + + @Test + public void testGetAllLocations() { + when(properties.getConnectionString()).thenReturn(azuriteConnectionString); + AzureBlobPayloadStorage azureBlobPayloadStorage = + new AzureBlobPayloadStorage(idGenerator, properties); + + testGetLocation( + azureBlobPayloadStorage, + ExternalPayloadStorage.Operation.READ, + ExternalPayloadStorage.PayloadType.WORKFLOW_INPUT, + properties.getWorkflowInputPath()); + testGetLocation( + azureBlobPayloadStorage, + ExternalPayloadStorage.Operation.READ, + ExternalPayloadStorage.PayloadType.WORKFLOW_OUTPUT, + properties.getWorkflowOutputPath()); + testGetLocation( + azureBlobPayloadStorage, + ExternalPayloadStorage.Operation.READ, + ExternalPayloadStorage.PayloadType.TASK_INPUT, + properties.getTaskInputPath()); + testGetLocation( + azureBlobPayloadStorage, + ExternalPayloadStorage.Operation.READ, + ExternalPayloadStorage.PayloadType.TASK_OUTPUT, + properties.getTaskOutputPath()); + + testGetLocation( + azureBlobPayloadStorage, + ExternalPayloadStorage.Operation.WRITE, + ExternalPayloadStorage.PayloadType.WORKFLOW_INPUT, + properties.getWorkflowInputPath()); + testGetLocation( + azureBlobPayloadStorage, + ExternalPayloadStorage.Operation.WRITE, + ExternalPayloadStorage.PayloadType.WORKFLOW_OUTPUT, + properties.getWorkflowOutputPath()); + testGetLocation( + azureBlobPayloadStorage, + ExternalPayloadStorage.Operation.WRITE, + ExternalPayloadStorage.PayloadType.TASK_INPUT, + properties.getTaskInputPath()); + testGetLocation( + azureBlobPayloadStorage, + ExternalPayloadStorage.Operation.WRITE, + ExternalPayloadStorage.PayloadType.TASK_OUTPUT, + properties.getTaskOutputPath()); + } +} diff --git a/build.gradle b/build.gradle index d99542949..c6ffda75d 100644 --- a/build.gradle +++ b/build.gradle @@ -8,34 +8,22 @@ buildscript { } } dependencies { - classpath 'com.netflix.nebula:gradle-extra-configurations-plugin:10.0.0' - classpath 'org.springframework.boot:spring-boot-gradle-plugin:2.7.16' + classpath 'org.springframework.boot:spring-boot-gradle-plugin:3.1.4' classpath 'com.diffplug.spotless:spotless-plugin-gradle:6.+' } } plugins { - id 'io.spring.dependency-management' version '1.1.3' + id 'io.spring.dependency-management' version '1.0.13.RELEASE' id 'java' id 'application' - id 'jacoco' - id 'com.netflix.nebula.netflixoss' version '11.3.2' - id 'org.sonarqube' version '3.4.0.2513' + id 'maven-publish' + id 'signing' + id 'java-library' + id "com.diffplug.spotless" version "6.25.0" + id 'org.springframework.boot' version '3.3.0' } -/* - * Copyright 2021 Netflix, Inc. - *

- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - */ - // Establish version and status ext.githubProjectName = rootProject.name // Change if github project name is not the same as the root project's name @@ -45,9 +33,9 @@ subprojects { apply from: "$rootDir/dependencies.gradle" apply from: "$rootDir/springboot-bom-overrides.gradle" +apply from: "$rootDir/deploy.gradle" allprojects { - apply plugin: 'com.netflix.nebula.netflixoss' apply plugin: 'io.spring.dependency-management' apply plugin: 'java-library' apply plugin: 'project-report' @@ -57,211 +45,68 @@ allprojects { languageVersion = JavaLanguageVersion.of(17) } } - - group = 'com.netflix.conductor' - - configurations.all { - exclude group: 'ch.qos.logback', module: 'logback-classic' - exclude group: 'ch.qos.logback', module: 'logback-core' - exclude group: 'org.apache.logging.log4j', module: 'log4j-to-slf4j' - exclude group: 'org.slf4j', module: 'slf4j-log4j12' - resolutionStrategy { - force 'org.codehaus.jettison:jettison:1.5.4' - force "org.apache.commons:commons-compress:${revCommonsCompress}" + + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 + + group = 'org.conductoross' + + configurations { + all { + exclude group: 'ch.qos.logback', module: 'logback-classic' + exclude group: 'ch.qos.logback', module: 'logback-core' + exclude group: 'org.apache.logging.log4j', module: 'log4j-to-slf4j' + exclude group: 'org.slf4j', module: 'slf4j-log4j12' + + resolutionStrategy.eachDependency { details -> + if (details.requested.group.startsWith('com.fasterxml.jackson.') ) { + details.useVersion "2.15.2" + } + } } } repositories { mavenCentral() - - // oss-candidate for -rc.* verions: - maven { - url "https://artifactory-oss.prod.netflix.net/artifactory/maven-oss-candidates" - } - - /** - * This repository locates artifacts that don't exist in maven central but we had to backup from jcenter - * The exclusiveContent - */ - exclusiveContent { - forRepository { - maven { - url "https://artifactory-oss.prod.netflix.net/artifactory/required-jcenter-modules-backup" - } - } - filter { - includeGroupByRegex "com\\.github\\.vmg.*" - } - } } dependencyManagement { imports { - // dependency versions for the BOM can be found at https://docs.spring.io/spring-boot/docs/2.7.3/reference/htmlsingle/#appendix.dependency-versions + // dependency versions for the BOM can be found at https://docs.spring.io/spring-boot/docs/3.1.4/reference/htmlsingle/#appendix.dependency-versions mavenBom(SpringBootPlugin.BOM_COORDINATES) } } dependencies { - implementation('org.apache.logging.log4j:log4j-core') { - version { - // this is the preferred version this library will use - prefer '2.17.2' - // the strict bounds, effectively allowing any 2.x version greater than 2.17.2 - // could also remove the upper bound entirely if we wanted too - strictly '[2.17.2,3.0)' - } - } - implementation('org.apache.logging.log4j:log4j-api') { - version { - // this is the preferred version this library will use - prefer '2.17.2' - // the strict bounds, effectively allowing any 2.x version greater than 2.17.2 - // could also remove the upper bound entirely if we wanted too - strictly '[2.17.2,3.0)' - } - } - implementation('org.apache.logging.log4j:log4j-slf4j-impl') { - version { - // this is the preferred version this library will use - prefer '2.17.2' - // the strict bounds, effectively allowing any 2.x version greater than 2.17.2 - // could also remove the upper bound entirely if we wanted too - strictly '[2.17.2,3.0)' - } - } - implementation('org.apache.logging.log4j:log4j-jul') { - version { - // this is the preferred version this library will use - prefer '2.17.2' - // the strict bounds, effectively allowing any 2.x version greater than 2.17.2 - // could also remove the upper bound entirely if we wanted too - strictly '[2.17.2,3.0)' - } - } - implementation('org.apache.logging.log4j:log4j-web') { - version { - // this is the preferred version this library will use - prefer '2.17.2' - // the strict bounds, effectively allowing any 2.x version greater than 2.17.2 - // could also remove the upper bound entirely if we wanted too - strictly '[2.17.2,3.0)' - } - } - implementation('org.yaml:snakeyaml') { - version { - // this is the preferred version this library will use - prefer '2.0' - // the strict bounds, effectively allowing any 2.x version between 2.0 and 2.1 - strictly '[2.0,2.1)' - } - } - implementation('com.fasterxml.jackson.core:jackson-core') { - version { - // this is the preferred version this library will use - prefer '2.15.0' - // the strict bounds, effectively allowing any 2.15.x version between 2.15.0 and 2.15.2 - strictly '[2.15.0,2.15.2)' - } - } - implementation('com.fasterxml.jackson.core:jackson-databind') { - version { - // this is the preferred version this library will use - prefer '2.15.0' - // the strict bounds, effectively allowing any 2.15.x version between 2.15.0 and 2.15.2 - strictly '[2.15.0,2.15.2)' - } - } - implementation('com.fasterxml.jackson.dataformat:jackson-dataformat-yaml') { - version { - // this is the preferred version this library will use - prefer '2.15.0' - // the strict bounds, effectively allowing any 2.15.x version between 2.15.0 and 2.15.2 - strictly '[2.15.0,2.15.2)' - } - } - implementation('com.fasterxml.jackson.core:jackson-annotations') { - version { - // this is the preferred version this library will use - prefer '2.15.0' - // the strict bounds, effectively allowing any 2.15.x version between 2.15.0 and 2.15.2 - strictly '[2.15.0,2.15.2)' - } - } - implementation('com.fasterxml.jackson.dataformat:jackson-dataformat-smile') { - version { - // this is the preferred version this library will use - prefer '2.15.0' - // the strict bounds, effectively allowing any 2.15.x version between 2.15.0 and 2.15.2 - strictly '[2.15.0,2.15.2)' - } - } - implementation('com.fasterxml.jackson.dataformat:jackson-dataformat-cbor') { - version { - // this is the preferred version this library will use - prefer '2.15.0' - // the strict bounds, effectively allowing any 2.15.x version between 2.15.0 and 2.15.2 - strictly '[2.15.0,2.15.2)' - } - } - implementation('com.fasterxml.jackson.datatype:jackson-datatype-jdk8') { - version { - // this is the preferred version this library will use - prefer '2.15.0' - // the strict bounds, effectively allowing any 2.15.x version between 2.15.0 and 2.15.2 - strictly '[2.15.0,2.15.2)' - } - } - implementation('com.fasterxml.jackson.datatype:jackson-datatype-joda') { - version { - // this is the preferred version this library will use - prefer '2.15.0' - // the strict bounds, effectively allowing any 2.15.x version between 2.15.0 and 2.15.2 - strictly '[2.15.0,2.15.2)' - } - } - implementation('com.fasterxml.jackson.datatype:jackson-datatype-jsr310') { - version { - // this is the preferred version this library will use - prefer '2.15.0' - // the strict bounds, effectively allowing any 2.15.x version between 2.15.0 and 2.15.2 - strictly '[2.15.0,2.15.2)' - } - } - implementation('com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider') { - version { - // this is the preferred version this library will use - prefer '2.15.0' - // the strict bounds, effectively allowing any 2.15.x version between 2.15.0 and 2.15.2 - strictly '[2.15.0,2.15.2)' - } - } - implementation('com.fasterxml.jackson.module:jackson-module-afterburner') { - version { - // this is the preferred version this library will use - prefer '2.15.0' - // the strict bounds, effectively allowing any 2.15.x version between 2.15.0 and 2.15.2 - strictly '[2.15.0,2.15.2)' - } - } implementation('org.apache.logging.log4j:log4j-core') implementation('org.apache.logging.log4j:log4j-api') implementation('org.apache.logging.log4j:log4j-slf4j-impl') implementation('org.apache.logging.log4j:log4j-jul') - implementation('org.apache.logging.log4j:log4j-web') + implementation('org.apache.logging.log4j:log4j-web') + implementation "com.fasterxml.jackson.datatype:jackson-datatype-jsr310" + compileOnly 'org.projectlombok:lombok:1.18.34' + + annotationProcessor 'org.projectlombok:lombok:1.18.34' annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor' - testImplementation('org.springframework.boot:spring-boot-starter-test') { - exclude group: 'org.yaml', module: 'snakeyaml' - } + testImplementation('org.springframework.boot:spring-boot-starter-test') testImplementation('org.springframework.boot:spring-boot-starter-log4j2') testImplementation 'junit:junit' testImplementation "org.junit.vintage:junit-vintage-engine" + testAnnotationProcessor 'org.projectlombok:lombok:1.18.34' - // Needed for build to work on m1/m2 macs - testImplementation 'net.java.dev.jna:jna:5.13.0' + //Locks for the dependecies + implementation('org.codehaus.jettison:jettison') { + version { + strictly '1.5.4' + } + } + implementation('org.apache.tomcat.embed:tomcat-embed-core') { + version { + strictly '10.1.25' + } + } } - // processes additional configuration metadata json file as described here // https://docs.spring.io/spring-boot/docs/2.3.1.RELEASE/reference/html/appendix-configuration-metadata.html#configuration-metadata-additional-metadata compileJava.inputs.files(processResources) @@ -275,6 +120,9 @@ allprojects { showStandardStreams = false } } + bootJar { + enabled = false + } } // all client and their related modules are published with Java 17 compatibility @@ -286,26 +134,10 @@ allprojects { } } -jacocoTestReport { - reports { - html.required = true - xml.required = true - csv.required = false - } -} - task server { dependsOn ':conductor-server:bootRun' } -sonarqube { - properties { - property "sonar.projectKey", "com.netflix.conductor:conductor" - property "sonar.organization", "netflix" - property "sonar.host.url", "https://sonarcloud.io" - } -} - configure(allprojects - project(':conductor-grpc')) { apply plugin: 'com.diffplug.spotless' @@ -328,4 +160,4 @@ configure(allprojects - project(':conductor-grpc')) { } } } -} +} \ No newline at end of file diff --git a/cassandra-persistence/build.gradle b/cassandra-persistence/build.gradle index 6fee6f8ff..af1e8be2d 100644 --- a/cassandra-persistence/build.gradle +++ b/cassandra-persistence/build.gradle @@ -1,5 +1,5 @@ /* - * Copyright 2021 Netflix, Inc. + * Copyright 2023 Conductor authors *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at @@ -23,7 +23,7 @@ dependencies { testImplementation project(':conductor-core').sourceSets.test.output testImplementation project(':conductor-common').sourceSets.test.output - testImplementation "org.codehaus.groovy:groovy-all:${revGroovy}" + testImplementation "org.apache.groovy:groovy-all:${revGroovy}" testImplementation "org.spockframework:spock-core:${revSpock}" testImplementation "org.spockframework:spock-spring:${revSpock}" testImplementation "org.testcontainers:spock:${revTestContainer}" diff --git a/cassandra-persistence/dependencies.lock b/cassandra-persistence/dependencies.lock deleted file mode 100644 index 18ff44084..000000000 --- a/cassandra-persistence/dependencies.lock +++ /dev/null @@ -1,665 +0,0 @@ -{ - "annotationProcessor": { - "org.springframework.boot:spring-boot-configuration-processor": { - "locked": "2.7.16" - } - }, - "compileClasspath": { - "com.datastax.cassandra:cassandra-driver-core": { - "locked": "3.10.2" - }, - "com.fasterxml.jackson.core:jackson-annotations": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.core:jackson-core": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.core:jackson-databind": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.dataformat:jackson-dataformat-cbor": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.dataformat:jackson-dataformat-smile": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.dataformat:jackson-dataformat-yaml": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.datatype:jackson-datatype-jdk8": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.datatype:jackson-datatype-joda": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.datatype:jackson-datatype-jsr310": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.module:jackson-module-afterburner": { - "locked": "2.15.0" - }, - "com.netflix.conductor:conductor-common": { - "project": true - }, - "com.netflix.conductor:conductor-core": { - "project": true - }, - "org.apache.commons:commons-lang3": { - "locked": "3.12.0" - }, - "org.apache.logging.log4j:log4j-api": { - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-core": { - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-jul": { - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-slf4j-impl": { - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-web": { - "locked": "2.17.2" - }, - "org.springframework.boot:spring-boot-starter": { - "locked": "2.7.16" - }, - "org.yaml:snakeyaml": { - "locked": "2.0" - } - }, - "runtimeClasspath": { - "com.datastax.cassandra:cassandra-driver-core": { - "locked": "3.10.2" - }, - "com.fasterxml.jackson.core:jackson-annotations": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.core:jackson-core": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.core:jackson-databind": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.dataformat:jackson-dataformat-cbor": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.dataformat:jackson-dataformat-smile": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.dataformat:jackson-dataformat-yaml": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.datatype:jackson-datatype-jdk8": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.datatype:jackson-datatype-joda": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.datatype:jackson-datatype-jsr310": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.module:jackson-module-afterburner": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "2.15.0" - }, - "com.github.ben-manes.caffeine:caffeine": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-core" - ], - "locked": "2.9.3" - }, - "com.google.protobuf:protobuf-java": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "3.24.3" - }, - "com.jayway.jsonpath:json-path": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-core" - ], - "locked": "2.7.0" - }, - "com.netflix.conductor:conductor-annotations": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-common" - ], - "project": true - }, - "com.netflix.conductor:conductor-common": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-core" - ], - "project": true - }, - "com.netflix.conductor:conductor-core": { - "project": true - }, - "com.netflix.spectator:spectator-api": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-core" - ], - "locked": "0.122.0" - }, - "com.spotify:completable-futures": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-core" - ], - "locked": "0.3.3" - }, - "commons-io:commons-io": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-core" - ], - "locked": "2.7" - }, - "io.reactivex:rxjava": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-core" - ], - "locked": "1.3.8" - }, - "jakarta.activation:jakarta.activation-api": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-core" - ], - "locked": "1.2.2" - }, - "jakarta.xml.bind:jakarta.xml.bind-api": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-core" - ], - "locked": "2.3.3" - }, - "org.apache.bval:bval-jsr": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "2.0.6" - }, - "org.apache.commons:commons-lang3": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "3.12.0" - }, - "org.apache.logging.log4j:log4j-api": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-core": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-jul": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-slf4j-impl": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-web": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "2.17.2" - }, - "org.openjdk.nashorn:nashorn-core": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-core" - ], - "locked": "15.4" - }, - "org.yaml:snakeyaml": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "2.0" - } - }, - "testCompileClasspath": { - "com.datastax.cassandra:cassandra-driver-core": { - "locked": "3.10.2" - }, - "com.fasterxml.jackson.core:jackson-annotations": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.core:jackson-core": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.core:jackson-databind": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.dataformat:jackson-dataformat-cbor": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.dataformat:jackson-dataformat-smile": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.dataformat:jackson-dataformat-yaml": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.datatype:jackson-datatype-jdk8": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.datatype:jackson-datatype-joda": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.datatype:jackson-datatype-jsr310": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.module:jackson-module-afterburner": { - "locked": "2.15.0" - }, - "com.google.protobuf:protobuf-java": { - "locked": "3.24.3" - }, - "com.netflix.conductor:conductor-common": { - "project": true - }, - "com.netflix.conductor:conductor-core": { - "project": true - }, - "junit:junit": { - "locked": "4.13.2" - }, - "net.java.dev.jna:jna": { - "locked": "5.13.0" - }, - "org.apache.commons:commons-lang3": { - "locked": "3.12.0" - }, - "org.apache.logging.log4j:log4j-api": { - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-core": { - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-jul": { - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-slf4j-impl": { - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-web": { - "locked": "2.17.2" - }, - "org.codehaus.groovy:groovy-all": { - "locked": "3.0.19" - }, - "org.junit.vintage:junit-vintage-engine": { - "locked": "5.8.2" - }, - "org.spockframework:spock-core": { - "locked": "2.3-groovy-3.0" - }, - "org.spockframework:spock-spring": { - "locked": "2.3-groovy-3.0" - }, - "org.springframework.boot:spring-boot-starter-log4j2": { - "locked": "2.7.16" - }, - "org.springframework.boot:spring-boot-starter-test": { - "locked": "2.7.16" - }, - "org.testcontainers:cassandra": { - "locked": "1.19.1" - }, - "org.testcontainers:spock": { - "locked": "1.19.1" - }, - "org.yaml:snakeyaml": { - "locked": "2.0" - } - }, - "testRuntimeClasspath": { - "com.datastax.cassandra:cassandra-driver-core": { - "locked": "3.10.2" - }, - "com.fasterxml.jackson.core:jackson-annotations": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.core:jackson-core": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.core:jackson-databind": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.dataformat:jackson-dataformat-cbor": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.dataformat:jackson-dataformat-smile": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.dataformat:jackson-dataformat-yaml": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.datatype:jackson-datatype-jdk8": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.datatype:jackson-datatype-joda": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.datatype:jackson-datatype-jsr310": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.module:jackson-module-afterburner": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "2.15.0" - }, - "com.github.ben-manes.caffeine:caffeine": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-core" - ], - "locked": "2.9.3" - }, - "com.google.protobuf:protobuf-java": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "3.24.3" - }, - "com.jayway.jsonpath:json-path": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-core" - ], - "locked": "2.7.0" - }, - "com.netflix.conductor:conductor-annotations": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-common" - ], - "project": true - }, - "com.netflix.conductor:conductor-common": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-core" - ], - "project": true - }, - "com.netflix.conductor:conductor-core": { - "project": true - }, - "com.netflix.spectator:spectator-api": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-core" - ], - "locked": "0.122.0" - }, - "com.spotify:completable-futures": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-core" - ], - "locked": "0.3.3" - }, - "commons-io:commons-io": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-core" - ], - "locked": "2.7" - }, - "io.reactivex:rxjava": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-core" - ], - "locked": "1.3.8" - }, - "jakarta.activation:jakarta.activation-api": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-core" - ], - "locked": "1.2.2" - }, - "jakarta.xml.bind:jakarta.xml.bind-api": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-core" - ], - "locked": "2.3.3" - }, - "junit:junit": { - "locked": "4.13.2" - }, - "net.java.dev.jna:jna": { - "locked": "5.13.0" - }, - "org.apache.bval:bval-jsr": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "2.0.6" - }, - "org.apache.commons:commons-lang3": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "3.12.0" - }, - "org.apache.logging.log4j:log4j-api": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-core": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-jul": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-slf4j-impl": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-web": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "2.17.2" - }, - "org.codehaus.groovy:groovy-all": { - "locked": "3.0.19" - }, - "org.junit.vintage:junit-vintage-engine": { - "locked": "5.8.2" - }, - "org.openjdk.nashorn:nashorn-core": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-core" - ], - "locked": "15.4" - }, - "org.spockframework:spock-core": { - "locked": "2.3-groovy-3.0" - }, - "org.spockframework:spock-spring": { - "locked": "2.3-groovy-3.0" - }, - "org.springframework.boot:spring-boot-starter-log4j2": { - "locked": "2.7.16" - }, - "org.springframework.boot:spring-boot-starter-test": { - "locked": "2.7.16" - }, - "org.testcontainers:cassandra": { - "locked": "1.19.1" - }, - "org.testcontainers:spock": { - "locked": "1.19.1" - }, - "org.yaml:snakeyaml": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-core" - ], - "locked": "2.0" - } - } -} \ No newline at end of file diff --git a/cassandra-persistence/src/main/java/com/netflix/conductor/cassandra/config/CassandraConfiguration.java b/cassandra-persistence/src/main/java/com/netflix/conductor/cassandra/config/CassandraConfiguration.java index 14c3c022b..f415aa55f 100644 --- a/cassandra-persistence/src/main/java/com/netflix/conductor/cassandra/config/CassandraConfiguration.java +++ b/cassandra-persistence/src/main/java/com/netflix/conductor/cassandra/config/CassandraConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/cassandra-persistence/src/main/java/com/netflix/conductor/cassandra/config/CassandraProperties.java b/cassandra-persistence/src/main/java/com/netflix/conductor/cassandra/config/CassandraProperties.java index 28d3eee97..37ca274de 100644 --- a/cassandra-persistence/src/main/java/com/netflix/conductor/cassandra/config/CassandraProperties.java +++ b/cassandra-persistence/src/main/java/com/netflix/conductor/cassandra/config/CassandraProperties.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/cassandra-persistence/src/main/java/com/netflix/conductor/cassandra/config/cache/CacheableEventHandlerDAO.java b/cassandra-persistence/src/main/java/com/netflix/conductor/cassandra/config/cache/CacheableEventHandlerDAO.java index 6f4b8bee1..4973e811e 100644 --- a/cassandra-persistence/src/main/java/com/netflix/conductor/cassandra/config/cache/CacheableEventHandlerDAO.java +++ b/cassandra-persistence/src/main/java/com/netflix/conductor/cassandra/config/cache/CacheableEventHandlerDAO.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at @@ -20,8 +20,6 @@ import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; -import javax.annotation.PostConstruct; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.cache.Cache; @@ -36,6 +34,8 @@ import com.netflix.conductor.dao.EventHandlerDAO; import com.netflix.conductor.metrics.Monitors; +import jakarta.annotation.PostConstruct; + import static com.netflix.conductor.cassandra.config.cache.CachingConfig.EVENT_HANDLER_CACHE; @Trace diff --git a/cassandra-persistence/src/main/java/com/netflix/conductor/cassandra/config/cache/CacheableMetadataDAO.java b/cassandra-persistence/src/main/java/com/netflix/conductor/cassandra/config/cache/CacheableMetadataDAO.java index 256512ea4..7ccdeb96a 100644 --- a/cassandra-persistence/src/main/java/com/netflix/conductor/cassandra/config/cache/CacheableMetadataDAO.java +++ b/cassandra-persistence/src/main/java/com/netflix/conductor/cassandra/config/cache/CacheableMetadataDAO.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at @@ -20,8 +20,6 @@ import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; -import javax.annotation.PostConstruct; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.cache.Cache; @@ -38,6 +36,8 @@ import com.netflix.conductor.dao.MetadataDAO; import com.netflix.conductor.metrics.Monitors; +import jakarta.annotation.PostConstruct; + import static com.netflix.conductor.cassandra.config.cache.CachingConfig.TASK_DEF_CACHE; @Trace diff --git a/cassandra-persistence/src/main/java/com/netflix/conductor/cassandra/config/cache/CachingConfig.java b/cassandra-persistence/src/main/java/com/netflix/conductor/cassandra/config/cache/CachingConfig.java index bd0f178f5..6255ce47e 100644 --- a/cassandra-persistence/src/main/java/com/netflix/conductor/cassandra/config/cache/CachingConfig.java +++ b/cassandra-persistence/src/main/java/com/netflix/conductor/cassandra/config/cache/CachingConfig.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/cassandra-persistence/src/main/java/com/netflix/conductor/cassandra/dao/CassandraBaseDAO.java b/cassandra-persistence/src/main/java/com/netflix/conductor/cassandra/dao/CassandraBaseDAO.java index b327c18fb..e6fb4b27a 100644 --- a/cassandra-persistence/src/main/java/com/netflix/conductor/cassandra/dao/CassandraBaseDAO.java +++ b/cassandra-persistence/src/main/java/com/netflix/conductor/cassandra/dao/CassandraBaseDAO.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/cassandra-persistence/src/main/java/com/netflix/conductor/cassandra/dao/CassandraEventHandlerDAO.java b/cassandra-persistence/src/main/java/com/netflix/conductor/cassandra/dao/CassandraEventHandlerDAO.java index 4fa72a2ea..db6e1fadf 100644 --- a/cassandra-persistence/src/main/java/com/netflix/conductor/cassandra/dao/CassandraEventHandlerDAO.java +++ b/cassandra-persistence/src/main/java/com/netflix/conductor/cassandra/dao/CassandraEventHandlerDAO.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/cassandra-persistence/src/main/java/com/netflix/conductor/cassandra/dao/CassandraExecutionDAO.java b/cassandra-persistence/src/main/java/com/netflix/conductor/cassandra/dao/CassandraExecutionDAO.java index ce564af0a..6ced38b8d 100644 --- a/cassandra-persistence/src/main/java/com/netflix/conductor/cassandra/dao/CassandraExecutionDAO.java +++ b/cassandra-persistence/src/main/java/com/netflix/conductor/cassandra/dao/CassandraExecutionDAO.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/cassandra-persistence/src/main/java/com/netflix/conductor/cassandra/dao/CassandraMetadataDAO.java b/cassandra-persistence/src/main/java/com/netflix/conductor/cassandra/dao/CassandraMetadataDAO.java index 90ff3ed4a..9c6de6438 100644 --- a/cassandra-persistence/src/main/java/com/netflix/conductor/cassandra/dao/CassandraMetadataDAO.java +++ b/cassandra-persistence/src/main/java/com/netflix/conductor/cassandra/dao/CassandraMetadataDAO.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/cassandra-persistence/src/main/java/com/netflix/conductor/cassandra/dao/CassandraPollDataDAO.java b/cassandra-persistence/src/main/java/com/netflix/conductor/cassandra/dao/CassandraPollDataDAO.java index 235dd44f4..8e7e4d1e3 100644 --- a/cassandra-persistence/src/main/java/com/netflix/conductor/cassandra/dao/CassandraPollDataDAO.java +++ b/cassandra-persistence/src/main/java/com/netflix/conductor/cassandra/dao/CassandraPollDataDAO.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/cassandra-persistence/src/main/java/com/netflix/conductor/cassandra/util/Constants.java b/cassandra-persistence/src/main/java/com/netflix/conductor/cassandra/util/Constants.java index 473c23132..1d815ae62 100644 --- a/cassandra-persistence/src/main/java/com/netflix/conductor/cassandra/util/Constants.java +++ b/cassandra-persistence/src/main/java/com/netflix/conductor/cassandra/util/Constants.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/cassandra-persistence/src/main/java/com/netflix/conductor/cassandra/util/Statements.java b/cassandra-persistence/src/main/java/com/netflix/conductor/cassandra/util/Statements.java index 68fe3b242..63e6b4a06 100644 --- a/cassandra-persistence/src/main/java/com/netflix/conductor/cassandra/util/Statements.java +++ b/cassandra-persistence/src/main/java/com/netflix/conductor/cassandra/util/Statements.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/cassandra-persistence/src/test/groovy/com/netflix/conductor/cassandra/dao/CassandraEventHandlerDAOSpec.groovy b/cassandra-persistence/src/test/groovy/com/netflix/conductor/cassandra/dao/CassandraEventHandlerDAOSpec.groovy index 214f3722d..e0d437d7b 100644 --- a/cassandra-persistence/src/test/groovy/com/netflix/conductor/cassandra/dao/CassandraEventHandlerDAOSpec.groovy +++ b/cassandra-persistence/src/test/groovy/com/netflix/conductor/cassandra/dao/CassandraEventHandlerDAOSpec.groovy @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/cassandra-persistence/src/test/groovy/com/netflix/conductor/cassandra/dao/CassandraExecutionDAOSpec.groovy b/cassandra-persistence/src/test/groovy/com/netflix/conductor/cassandra/dao/CassandraExecutionDAOSpec.groovy index 14f612967..e438f4a88 100644 --- a/cassandra-persistence/src/test/groovy/com/netflix/conductor/cassandra/dao/CassandraExecutionDAOSpec.groovy +++ b/cassandra-persistence/src/test/groovy/com/netflix/conductor/cassandra/dao/CassandraExecutionDAOSpec.groovy @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at @@ -403,44 +403,6 @@ class CassandraExecutionDAOSpec extends CassandraSpec { eventExecutionList != null && eventExecutionList.empty } - def "verify workflow serialization"() { - given: 'define a workflow' - String workflowId = new IDGenerator().generate() - WorkflowTask workflowTask = new WorkflowTask(taskDefinition: new TaskDef(concurrentExecLimit: 2)) - WorkflowDef workflowDef = new WorkflowDef(name: UUID.randomUUID().toString(), version: 1, tasks: [workflowTask]) - WorkflowModel workflow = new WorkflowModel(workflowDefinition: workflowDef, workflowId: workflowId, status: WorkflowModel.Status.RUNNING, createTime: System.currentTimeMillis()) - - when: 'serialize workflow' - def workflowJson = objectMapper.writeValueAsString(workflow) - - then: - !workflowJson.contains('failedReferenceTaskNames') - // workflowTask - !workflowJson.contains('decisionCases') - !workflowJson.contains('defaultCase') - !workflowJson.contains('forkTasks') - !workflowJson.contains('joinOn') - !workflowJson.contains('defaultExclusiveJoinTask') - !workflowJson.contains('loopOver') - } - - def "verify task serialization"() { - given: 'define a workflow and tasks for this workflow' - String workflowId = new IDGenerator().generate() - WorkflowTask workflowTask = new WorkflowTask(taskDefinition: new TaskDef(concurrentExecLimit: 2)) - TaskModel task = new TaskModel(workflowInstanceId: workflowId, taskType: UUID.randomUUID().toString(), referenceTaskName: UUID.randomUUID().toString(), status: TaskModel.Status.SCHEDULED, taskId: new IDGenerator().generate(), workflowTask: workflowTask) - - when: 'serialize task' - def taskJson = objectMapper.writeValueAsString(task) - - then: - !taskJson.contains('decisionCases') - !taskJson.contains('defaultCase') - !taskJson.contains('forkTasks') - !taskJson.contains('joinOn') - !taskJson.contains('defaultExclusiveJoinTask') - } - def "serde of workflow with large number of tasks"() { given: 'create a workflow and tasks for this workflow' String workflowId = new IDGenerator().generate() diff --git a/cassandra-persistence/src/test/groovy/com/netflix/conductor/cassandra/dao/CassandraMetadataDAOSpec.groovy b/cassandra-persistence/src/test/groovy/com/netflix/conductor/cassandra/dao/CassandraMetadataDAOSpec.groovy index fd8afacc5..498435cdc 100644 --- a/cassandra-persistence/src/test/groovy/com/netflix/conductor/cassandra/dao/CassandraMetadataDAOSpec.groovy +++ b/cassandra-persistence/src/test/groovy/com/netflix/conductor/cassandra/dao/CassandraMetadataDAOSpec.groovy @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/cassandra-persistence/src/test/groovy/com/netflix/conductor/cassandra/dao/CassandraSpec.groovy b/cassandra-persistence/src/test/groovy/com/netflix/conductor/cassandra/dao/CassandraSpec.groovy index a5393210b..935788e89 100644 --- a/cassandra-persistence/src/test/groovy/com/netflix/conductor/cassandra/dao/CassandraSpec.groovy +++ b/cassandra-persistence/src/test/groovy/com/netflix/conductor/cassandra/dao/CassandraSpec.groovy @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/cassandra-persistence/src/test/groovy/com/netflix/conductor/cassandra/util/StatementsSpec.groovy b/cassandra-persistence/src/test/groovy/com/netflix/conductor/cassandra/util/StatementsSpec.groovy index f826a3620..8517e7e4a 100644 --- a/cassandra-persistence/src/test/groovy/com/netflix/conductor/cassandra/util/StatementsSpec.groovy +++ b/cassandra-persistence/src/test/groovy/com/netflix/conductor/cassandra/util/StatementsSpec.groovy @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/client-spring/dependencies.lock b/client-spring/dependencies.lock deleted file mode 100644 index 9602d6246..000000000 --- a/client-spring/dependencies.lock +++ /dev/null @@ -1,709 +0,0 @@ -{ - "annotationProcessor": { - "org.springframework.boot:spring-boot-configuration-processor": { - "locked": "2.7.16" - } - }, - "compileClasspath": { - "com.fasterxml.jackson.core:jackson-annotations": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.core:jackson-core": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.core:jackson-databind": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.dataformat:jackson-dataformat-cbor": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.dataformat:jackson-dataformat-smile": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.dataformat:jackson-dataformat-yaml": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.datatype:jackson-datatype-jdk8": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.datatype:jackson-datatype-joda": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.datatype:jackson-datatype-jsr310": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.module:jackson-module-afterburner": { - "locked": "2.15.0" - }, - "com.netflix.conductor:conductor-client": { - "project": true - }, - "com.netflix.conductor:conductor-common": { - "project": true - }, - "com.netflix.conductor:conductor-java-sdk": { - "project": true - }, - "com.netflix.eureka:eureka-client": { - "locked": "1.10.10" - }, - "org.apache.logging.log4j:log4j-api": { - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-core": { - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-jul": { - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-slf4j-impl": { - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-web": { - "locked": "2.17.2" - }, - "org.springframework.boot:spring-boot-starter": { - "locked": "2.7.16" - }, - "org.yaml:snakeyaml": { - "locked": "2.0" - } - }, - "runtimeClasspath": { - "cglib:cglib": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-java-sdk" - ], - "locked": "3.3.0" - }, - "com.amazonaws:aws-java-sdk-core": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-client" - ], - "locked": "1.12.535" - }, - "com.fasterxml.jackson.core:jackson-annotations": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-client", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-java-sdk" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.core:jackson-core": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-client", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-java-sdk" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.core:jackson-databind": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-client", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-java-sdk" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.dataformat:jackson-dataformat-cbor": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-client", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-java-sdk" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.dataformat:jackson-dataformat-smile": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-client", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-java-sdk" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.dataformat:jackson-dataformat-yaml": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-client", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-java-sdk" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.datatype:jackson-datatype-jdk8": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-client", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-java-sdk" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.datatype:jackson-datatype-joda": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-client", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-java-sdk" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.datatype:jackson-datatype-jsr310": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-client", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-java-sdk" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-client", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-java-sdk" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.module:jackson-module-afterburner": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-client", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-java-sdk" - ], - "locked": "2.15.0" - }, - "com.google.guava:guava": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-java-sdk" - ], - "locked": "32.1.2-jre" - }, - "com.google.protobuf:protobuf-java": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-common" - ], - "locked": "3.24.3" - }, - "com.netflix.conductor:conductor-annotations": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-common" - ], - "project": true - }, - "com.netflix.conductor:conductor-client": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-java-sdk" - ], - "project": true - }, - "com.netflix.conductor:conductor-common": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-client", - "com.netflix.conductor:conductor-java-sdk" - ], - "project": true - }, - "com.netflix.conductor:conductor-java-sdk": { - "project": true - }, - "com.netflix.eureka:eureka-client": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-client" - ], - "locked": "1.10.10" - }, - "com.netflix.spectator:spectator-api": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-client" - ], - "locked": "0.122.0" - }, - "com.sun.jersey:jersey-client": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-client", - "com.netflix.conductor:conductor-java-sdk" - ], - "locked": "1.19.4" - }, - "commons-io:commons-io": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-client" - ], - "locked": "2.7" - }, - "javax.ws.rs:javax.ws.rs-api": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-client", - "com.netflix.conductor:conductor-java-sdk" - ], - "locked": "2.1.1" - }, - "org.apache.bval:bval-jsr": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-common" - ], - "locked": "2.0.6" - }, - "org.apache.commons:commons-lang3": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-client", - "com.netflix.conductor:conductor-common" - ], - "locked": "3.12.0" - }, - "org.apache.logging.log4j:log4j-api": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-client", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-java-sdk" - ], - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-core": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-client", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-java-sdk" - ], - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-jul": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-client", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-java-sdk" - ], - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-slf4j-impl": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-client", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-java-sdk" - ], - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-web": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-client", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-java-sdk" - ], - "locked": "2.17.2" - }, - "org.glassfish.jersey.core:jersey-common": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-client", - "com.netflix.conductor:conductor-java-sdk" - ], - "locked": "2.35" - }, - "org.openjdk.nashorn:nashorn-core": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-java-sdk" - ], - "locked": "15.4" - }, - "org.slf4j:slf4j-api": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-client" - ], - "locked": "1.7.36" - }, - "org.springframework.boot:spring-boot-starter": { - "locked": "2.7.16" - }, - "org.yaml:snakeyaml": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-client", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-java-sdk" - ], - "locked": "2.0" - } - }, - "testCompileClasspath": { - "com.fasterxml.jackson.core:jackson-annotations": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.core:jackson-core": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.core:jackson-databind": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.dataformat:jackson-dataformat-cbor": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.dataformat:jackson-dataformat-smile": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.dataformat:jackson-dataformat-yaml": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.datatype:jackson-datatype-jdk8": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.datatype:jackson-datatype-joda": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.datatype:jackson-datatype-jsr310": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.module:jackson-module-afterburner": { - "locked": "2.15.0" - }, - "com.netflix.conductor:conductor-client": { - "project": true - }, - "com.netflix.conductor:conductor-common": { - "project": true - }, - "com.netflix.conductor:conductor-java-sdk": { - "project": true - }, - "com.netflix.eureka:eureka-client": { - "locked": "1.10.10" - }, - "junit:junit": { - "locked": "4.13.2" - }, - "net.java.dev.jna:jna": { - "locked": "5.13.0" - }, - "org.apache.logging.log4j:log4j-api": { - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-core": { - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-jul": { - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-slf4j-impl": { - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-web": { - "locked": "2.17.2" - }, - "org.junit.vintage:junit-vintage-engine": { - "locked": "5.8.2" - }, - "org.springframework.boot:spring-boot-starter": { - "locked": "2.7.16" - }, - "org.springframework.boot:spring-boot-starter-log4j2": { - "locked": "2.7.16" - }, - "org.springframework.boot:spring-boot-starter-test": { - "locked": "2.7.16" - }, - "org.yaml:snakeyaml": { - "locked": "2.0" - } - }, - "testRuntimeClasspath": { - "cglib:cglib": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-java-sdk" - ], - "locked": "3.3.0" - }, - "com.amazonaws:aws-java-sdk-core": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-client" - ], - "locked": "1.12.535" - }, - "com.fasterxml.jackson.core:jackson-annotations": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-client", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-java-sdk" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.core:jackson-core": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-client", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-java-sdk" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.core:jackson-databind": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-client", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-java-sdk" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.dataformat:jackson-dataformat-cbor": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-client", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-java-sdk" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.dataformat:jackson-dataformat-smile": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-client", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-java-sdk" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.dataformat:jackson-dataformat-yaml": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-client", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-java-sdk" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.datatype:jackson-datatype-jdk8": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-client", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-java-sdk" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.datatype:jackson-datatype-joda": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-client", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-java-sdk" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.datatype:jackson-datatype-jsr310": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-client", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-java-sdk" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-client", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-java-sdk" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.module:jackson-module-afterburner": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-client", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-java-sdk" - ], - "locked": "2.15.0" - }, - "com.google.guava:guava": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-java-sdk" - ], - "locked": "32.1.2-jre" - }, - "com.google.protobuf:protobuf-java": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-common" - ], - "locked": "3.24.3" - }, - "com.netflix.conductor:conductor-annotations": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-common" - ], - "project": true - }, - "com.netflix.conductor:conductor-client": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-java-sdk" - ], - "project": true - }, - "com.netflix.conductor:conductor-common": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-client", - "com.netflix.conductor:conductor-java-sdk" - ], - "project": true - }, - "com.netflix.conductor:conductor-java-sdk": { - "project": true - }, - "com.netflix.eureka:eureka-client": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-client" - ], - "locked": "1.10.10" - }, - "com.netflix.spectator:spectator-api": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-client" - ], - "locked": "0.122.0" - }, - "com.sun.jersey:jersey-client": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-client", - "com.netflix.conductor:conductor-java-sdk" - ], - "locked": "1.19.4" - }, - "commons-io:commons-io": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-client" - ], - "locked": "2.7" - }, - "javax.ws.rs:javax.ws.rs-api": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-client", - "com.netflix.conductor:conductor-java-sdk" - ], - "locked": "2.1.1" - }, - "junit:junit": { - "locked": "4.13.2" - }, - "net.java.dev.jna:jna": { - "locked": "5.13.0" - }, - "org.apache.bval:bval-jsr": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-common" - ], - "locked": "2.0.6" - }, - "org.apache.commons:commons-lang3": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-client", - "com.netflix.conductor:conductor-common" - ], - "locked": "3.12.0" - }, - "org.apache.logging.log4j:log4j-api": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-client", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-java-sdk" - ], - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-core": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-client", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-java-sdk" - ], - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-jul": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-client", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-java-sdk" - ], - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-slf4j-impl": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-client", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-java-sdk" - ], - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-web": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-client", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-java-sdk" - ], - "locked": "2.17.2" - }, - "org.glassfish.jersey.core:jersey-common": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-client", - "com.netflix.conductor:conductor-java-sdk" - ], - "locked": "2.35" - }, - "org.junit.vintage:junit-vintage-engine": { - "locked": "5.8.2" - }, - "org.openjdk.nashorn:nashorn-core": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-java-sdk" - ], - "locked": "15.4" - }, - "org.slf4j:slf4j-api": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-client" - ], - "locked": "1.7.36" - }, - "org.springframework.boot:spring-boot-starter": { - "locked": "2.7.16" - }, - "org.springframework.boot:spring-boot-starter-log4j2": { - "locked": "2.7.16" - }, - "org.springframework.boot:spring-boot-starter-test": { - "locked": "2.7.16" - }, - "org.yaml:snakeyaml": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-client", - "com.netflix.conductor:conductor-common", - "com.netflix.conductor:conductor-java-sdk" - ], - "locked": "2.0" - } - } -} \ No newline at end of file diff --git a/client-spring/src/main/java/com/netflix/conductor/client/spring/ClientProperties.java b/client-spring/src/main/java/com/netflix/conductor/client/spring/ClientProperties.java index 55c82e576..87b13cbfe 100644 --- a/client-spring/src/main/java/com/netflix/conductor/client/spring/ClientProperties.java +++ b/client-spring/src/main/java/com/netflix/conductor/client/spring/ClientProperties.java @@ -1,5 +1,5 @@ /* - * Copyright 2020 Netflix, Inc. + * Copyright 2020 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/client-spring/src/main/java/com/netflix/conductor/client/spring/ConductorClientAutoConfiguration.java b/client-spring/src/main/java/com/netflix/conductor/client/spring/ConductorClientAutoConfiguration.java index a730f24eb..0219edbf1 100644 --- a/client-spring/src/main/java/com/netflix/conductor/client/spring/ConductorClientAutoConfiguration.java +++ b/client-spring/src/main/java/com/netflix/conductor/client/spring/ConductorClientAutoConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2020 Netflix, Inc. + * Copyright 2020 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/client-spring/src/main/java/com/netflix/conductor/client/spring/ConductorWorkerAutoConfiguration.java b/client-spring/src/main/java/com/netflix/conductor/client/spring/ConductorWorkerAutoConfiguration.java index 94d69bbde..dd6983f33 100644 --- a/client-spring/src/main/java/com/netflix/conductor/client/spring/ConductorWorkerAutoConfiguration.java +++ b/client-spring/src/main/java/com/netflix/conductor/client/spring/ConductorWorkerAutoConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2023 Netflix, Inc. + * Copyright 2023 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/client-spring/src/main/java/com/netflix/conductor/client/spring/SpringWorkerConfiguration.java b/client-spring/src/main/java/com/netflix/conductor/client/spring/SpringWorkerConfiguration.java index 6d44e779c..231bf92e4 100644 --- a/client-spring/src/main/java/com/netflix/conductor/client/spring/SpringWorkerConfiguration.java +++ b/client-spring/src/main/java/com/netflix/conductor/client/spring/SpringWorkerConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2023 Netflix, Inc. + * Copyright 2023 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/client-spring/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/client-spring/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 000000000..4cf1dd0b4 --- /dev/null +++ b/client-spring/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1 @@ +com.netflix.conductor.client.spring.ConductorClientAutoConfiguration \ No newline at end of file diff --git a/client-spring/src/test/java/com/netflix/conductor/client/spring/ExampleClient.java b/client-spring/src/test/java/com/netflix/conductor/client/spring/ExampleClient.java index 772c04dc0..4bca46e97 100644 --- a/client-spring/src/test/java/com/netflix/conductor/client/spring/ExampleClient.java +++ b/client-spring/src/test/java/com/netflix/conductor/client/spring/ExampleClient.java @@ -1,5 +1,5 @@ /* - * Copyright 2020 Netflix, Inc. + * Copyright 2020 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/client-spring/src/test/java/com/netflix/conductor/client/spring/Workers.java b/client-spring/src/test/java/com/netflix/conductor/client/spring/Workers.java index d28bf0c8d..8f1fb1a44 100644 --- a/client-spring/src/test/java/com/netflix/conductor/client/spring/Workers.java +++ b/client-spring/src/test/java/com/netflix/conductor/client/spring/Workers.java @@ -1,5 +1,5 @@ /* - * Copyright 2023 Netflix, Inc. + * Copyright 2023 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/client/build.gradle b/client/build.gradle index b16dd4e18..2ffd092ed 100644 --- a/client/build.gradle +++ b/client/build.gradle @@ -40,7 +40,7 @@ dependencies { testImplementation "org.powermock:powermock-module-junit4:${revPowerMock}" testImplementation "org.powermock:powermock-api-mockito2:${revPowerMock}" - testImplementation "org.codehaus.groovy:groovy-all:${revGroovy}" + testImplementation "org.apache.groovy:groovy-all:${revGroovy}" testImplementation "org.spockframework:spock-core:${revSpock}" testImplementation "org.spockframework:spock-spring:${revSpock}" } diff --git a/client/dependencies.lock b/client/dependencies.lock deleted file mode 100644 index 26b7763be..000000000 --- a/client/dependencies.lock +++ /dev/null @@ -1,580 +0,0 @@ -{ - "annotationProcessor": { - "org.springframework.boot:spring-boot-configuration-processor": { - "locked": "2.7.16" - } - }, - "compileClasspath": { - "com.amazonaws:aws-java-sdk-core": { - "locked": "1.12.535" - }, - "com.fasterxml.jackson.core:jackson-annotations": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.core:jackson-core": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.core:jackson-databind": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.dataformat:jackson-dataformat-cbor": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.dataformat:jackson-dataformat-smile": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.dataformat:jackson-dataformat-yaml": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.datatype:jackson-datatype-jdk8": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.datatype:jackson-datatype-joda": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.datatype:jackson-datatype-jsr310": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.module:jackson-module-afterburner": { - "locked": "2.15.0" - }, - "com.netflix.conductor:conductor-common": { - "project": true - }, - "com.netflix.eureka:eureka-client": { - "locked": "1.10.10" - }, - "com.netflix.spectator:spectator-api": { - "locked": "0.122.0" - }, - "com.sun.jersey:jersey-client": { - "locked": "1.19.4" - }, - "commons-io:commons-io": { - "locked": "2.7" - }, - "javax.ws.rs:javax.ws.rs-api": { - "locked": "2.1.1" - }, - "org.apache.commons:commons-lang3": { - "locked": "3.12.0" - }, - "org.apache.logging.log4j:log4j-api": { - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-core": { - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-jul": { - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-slf4j-impl": { - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-web": { - "locked": "2.17.2" - }, - "org.glassfish.jersey.core:jersey-common": { - "locked": "2.22.2" - }, - "org.jetbrains:annotations": { - "locked": "23.0.0" - }, - "org.slf4j:slf4j-api": { - "locked": "1.7.36" - }, - "org.yaml:snakeyaml": { - "locked": "2.0" - } - }, - "runtimeClasspath": { - "com.amazonaws:aws-java-sdk-core": { - "locked": "1.12.535" - }, - "com.fasterxml.jackson.core:jackson-annotations": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.core:jackson-core": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.core:jackson-databind": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.dataformat:jackson-dataformat-cbor": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.dataformat:jackson-dataformat-smile": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.dataformat:jackson-dataformat-yaml": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.datatype:jackson-datatype-jdk8": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.datatype:jackson-datatype-joda": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.datatype:jackson-datatype-jsr310": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.module:jackson-module-afterburner": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common" - ], - "locked": "2.15.0" - }, - "com.google.protobuf:protobuf-java": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-common" - ], - "locked": "3.24.3" - }, - "com.netflix.conductor:conductor-annotations": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-common" - ], - "project": true - }, - "com.netflix.conductor:conductor-common": { - "project": true - }, - "com.netflix.eureka:eureka-client": { - "locked": "1.10.10" - }, - "com.netflix.spectator:spectator-api": { - "locked": "0.122.0" - }, - "com.sun.jersey:jersey-client": { - "locked": "1.19.4" - }, - "commons-io:commons-io": { - "locked": "2.7" - }, - "javax.ws.rs:javax.ws.rs-api": { - "locked": "2.1.1" - }, - "org.apache.bval:bval-jsr": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-common" - ], - "locked": "2.0.6" - }, - "org.apache.commons:commons-lang3": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-common" - ], - "locked": "3.12.0" - }, - "org.apache.logging.log4j:log4j-api": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common" - ], - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-core": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common" - ], - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-jul": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common" - ], - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-slf4j-impl": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common" - ], - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-web": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common" - ], - "locked": "2.17.2" - }, - "org.glassfish.jersey.core:jersey-common": { - "locked": "2.22.2" - }, - "org.slf4j:slf4j-api": { - "locked": "1.7.36" - }, - "org.yaml:snakeyaml": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common" - ], - "locked": "2.0" - } - }, - "testCompileClasspath": { - "com.amazonaws:aws-java-sdk-core": { - "locked": "1.12.535" - }, - "com.fasterxml.jackson.core:jackson-annotations": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.core:jackson-core": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.core:jackson-databind": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.dataformat:jackson-dataformat-cbor": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.dataformat:jackson-dataformat-smile": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.dataformat:jackson-dataformat-yaml": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.datatype:jackson-datatype-jdk8": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.datatype:jackson-datatype-joda": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.datatype:jackson-datatype-jsr310": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.module:jackson-module-afterburner": { - "locked": "2.15.0" - }, - "com.netflix.conductor:conductor-common": { - "project": true - }, - "com.netflix.eureka:eureka-client": { - "locked": "1.10.10" - }, - "com.netflix.spectator:spectator-api": { - "locked": "0.122.0" - }, - "com.sun.jersey:jersey-client": { - "locked": "1.19.4" - }, - "commons-io:commons-io": { - "locked": "2.7" - }, - "javax.ws.rs:javax.ws.rs-api": { - "locked": "2.1.1" - }, - "junit:junit": { - "locked": "4.13.2" - }, - "net.java.dev.jna:jna": { - "locked": "5.13.0" - }, - "org.apache.commons:commons-lang3": { - "locked": "3.12.0" - }, - "org.apache.logging.log4j:log4j-api": { - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-core": { - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-jul": { - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-slf4j-impl": { - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-web": { - "locked": "2.17.2" - }, - "org.codehaus.groovy:groovy-all": { - "locked": "3.0.19" - }, - "org.glassfish.jersey.core:jersey-common": { - "locked": "2.22.2" - }, - "org.junit.vintage:junit-vintage-engine": { - "locked": "5.8.2" - }, - "org.powermock:powermock-api-mockito2": { - "locked": "2.0.9" - }, - "org.powermock:powermock-module-junit4": { - "locked": "2.0.9" - }, - "org.slf4j:slf4j-api": { - "locked": "1.7.36" - }, - "org.spockframework:spock-core": { - "locked": "2.3-groovy-3.0" - }, - "org.spockframework:spock-spring": { - "locked": "2.3-groovy-3.0" - }, - "org.springframework.boot:spring-boot-starter-log4j2": { - "locked": "2.7.16" - }, - "org.springframework.boot:spring-boot-starter-test": { - "locked": "2.7.16" - }, - "org.yaml:snakeyaml": { - "locked": "2.0" - } - }, - "testRuntimeClasspath": { - "com.amazonaws:aws-java-sdk-core": { - "locked": "1.12.535" - }, - "com.fasterxml.jackson.core:jackson-annotations": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.core:jackson-core": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.core:jackson-databind": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.dataformat:jackson-dataformat-cbor": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.dataformat:jackson-dataformat-smile": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.dataformat:jackson-dataformat-yaml": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.datatype:jackson-datatype-jdk8": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.datatype:jackson-datatype-joda": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.datatype:jackson-datatype-jsr310": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.module:jackson-module-afterburner": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common" - ], - "locked": "2.15.0" - }, - "com.google.protobuf:protobuf-java": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-common" - ], - "locked": "3.24.3" - }, - "com.netflix.conductor:conductor-annotations": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-common" - ], - "project": true - }, - "com.netflix.conductor:conductor-common": { - "project": true - }, - "com.netflix.eureka:eureka-client": { - "locked": "1.10.10" - }, - "com.netflix.spectator:spectator-api": { - "locked": "0.122.0" - }, - "com.sun.jersey:jersey-client": { - "locked": "1.19.4" - }, - "commons-io:commons-io": { - "locked": "2.7" - }, - "javax.ws.rs:javax.ws.rs-api": { - "locked": "2.1.1" - }, - "junit:junit": { - "locked": "4.13.2" - }, - "net.java.dev.jna:jna": { - "locked": "5.13.0" - }, - "org.apache.bval:bval-jsr": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-common" - ], - "locked": "2.0.6" - }, - "org.apache.commons:commons-lang3": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-common" - ], - "locked": "3.12.0" - }, - "org.apache.logging.log4j:log4j-api": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common" - ], - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-core": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common" - ], - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-jul": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common" - ], - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-slf4j-impl": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common" - ], - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-web": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common" - ], - "locked": "2.17.2" - }, - "org.codehaus.groovy:groovy-all": { - "locked": "3.0.19" - }, - "org.glassfish.jersey.core:jersey-common": { - "locked": "2.22.2" - }, - "org.junit.vintage:junit-vintage-engine": { - "locked": "5.8.2" - }, - "org.powermock:powermock-api-mockito2": { - "locked": "2.0.9" - }, - "org.powermock:powermock-module-junit4": { - "locked": "2.0.9" - }, - "org.slf4j:slf4j-api": { - "locked": "1.7.36" - }, - "org.spockframework:spock-core": { - "locked": "2.3-groovy-3.0" - }, - "org.spockframework:spock-spring": { - "locked": "2.3-groovy-3.0" - }, - "org.springframework.boot:spring-boot-starter-log4j2": { - "locked": "2.7.16" - }, - "org.springframework.boot:spring-boot-starter-test": { - "locked": "2.7.16" - }, - "org.yaml:snakeyaml": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common" - ], - "locked": "2.0" - } - } -} \ No newline at end of file diff --git a/client/src/main/java/com/netflix/conductor/client/automator/PollingSemaphore.java b/client/src/main/java/com/netflix/conductor/client/automator/PollingSemaphore.java index 334501fac..c4304c2d5 100644 --- a/client/src/main/java/com/netflix/conductor/client/automator/PollingSemaphore.java +++ b/client/src/main/java/com/netflix/conductor/client/automator/PollingSemaphore.java @@ -1,5 +1,5 @@ /* - * Copyright 2020 Netflix, Inc. + * Copyright 2020 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/client/src/main/java/com/netflix/conductor/client/automator/TaskPollExecutor.java b/client/src/main/java/com/netflix/conductor/client/automator/TaskPollExecutor.java index 3b011c93d..b0cb46c53 100644 --- a/client/src/main/java/com/netflix/conductor/client/automator/TaskPollExecutor.java +++ b/client/src/main/java/com/netflix/conductor/client/automator/TaskPollExecutor.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/client/src/main/java/com/netflix/conductor/client/automator/TaskRunnerConfigurer.java b/client/src/main/java/com/netflix/conductor/client/automator/TaskRunnerConfigurer.java index 3709f2aa5..3f740e6e4 100644 --- a/client/src/main/java/com/netflix/conductor/client/automator/TaskRunnerConfigurer.java +++ b/client/src/main/java/com/netflix/conductor/client/automator/TaskRunnerConfigurer.java @@ -1,5 +1,5 @@ /* - * Copyright 2020 Netflix, Inc. + * Copyright 2020 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/client/src/main/java/com/netflix/conductor/client/config/ConductorClientConfiguration.java b/client/src/main/java/com/netflix/conductor/client/config/ConductorClientConfiguration.java index 6c3029fa1..bb5a28926 100644 --- a/client/src/main/java/com/netflix/conductor/client/config/ConductorClientConfiguration.java +++ b/client/src/main/java/com/netflix/conductor/client/config/ConductorClientConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2018 Netflix, Inc. + * Copyright 2018 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/client/src/main/java/com/netflix/conductor/client/config/DefaultConductorClientConfiguration.java b/client/src/main/java/com/netflix/conductor/client/config/DefaultConductorClientConfiguration.java index f15cf3bab..13e7f3247 100644 --- a/client/src/main/java/com/netflix/conductor/client/config/DefaultConductorClientConfiguration.java +++ b/client/src/main/java/com/netflix/conductor/client/config/DefaultConductorClientConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2020 Netflix, Inc. + * Copyright 2020 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/client/src/main/java/com/netflix/conductor/client/config/PropertyFactory.java b/client/src/main/java/com/netflix/conductor/client/config/PropertyFactory.java index 443b85481..dcde89a37 100644 --- a/client/src/main/java/com/netflix/conductor/client/config/PropertyFactory.java +++ b/client/src/main/java/com/netflix/conductor/client/config/PropertyFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 2020 Netflix, Inc. + * Copyright 2020 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/client/src/main/java/com/netflix/conductor/client/exception/ConductorClientException.java b/client/src/main/java/com/netflix/conductor/client/exception/ConductorClientException.java index 5f3c79c00..a2af3a06b 100644 --- a/client/src/main/java/com/netflix/conductor/client/exception/ConductorClientException.java +++ b/client/src/main/java/com/netflix/conductor/client/exception/ConductorClientException.java @@ -1,5 +1,5 @@ /* - * Copyright 2020 Netflix, Inc. + * Copyright 2020 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/client/src/main/java/com/netflix/conductor/client/http/ClientBase.java b/client/src/main/java/com/netflix/conductor/client/http/ClientBase.java index a27da869d..5326abe4d 100644 --- a/client/src/main/java/com/netflix/conductor/client/http/ClientBase.java +++ b/client/src/main/java/com/netflix/conductor/client/http/ClientBase.java @@ -1,5 +1,5 @@ /* - * Copyright 2020 Netflix, Inc. + * Copyright 2020 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/client/src/main/java/com/netflix/conductor/client/http/ClientRequestHandler.java b/client/src/main/java/com/netflix/conductor/client/http/ClientRequestHandler.java index 38749c1c5..164cb579b 100644 --- a/client/src/main/java/com/netflix/conductor/client/http/ClientRequestHandler.java +++ b/client/src/main/java/com/netflix/conductor/client/http/ClientRequestHandler.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/client/src/main/java/com/netflix/conductor/client/http/EventClient.java b/client/src/main/java/com/netflix/conductor/client/http/EventClient.java index 660c2b44a..1782d0177 100644 --- a/client/src/main/java/com/netflix/conductor/client/http/EventClient.java +++ b/client/src/main/java/com/netflix/conductor/client/http/EventClient.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/client/src/main/java/com/netflix/conductor/client/http/MetadataClient.java b/client/src/main/java/com/netflix/conductor/client/http/MetadataClient.java index 8db927b8c..2db8df237 100644 --- a/client/src/main/java/com/netflix/conductor/client/http/MetadataClient.java +++ b/client/src/main/java/com/netflix/conductor/client/http/MetadataClient.java @@ -1,5 +1,5 @@ /* - * Copyright 2020 Netflix, Inc. + * Copyright 2020 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/client/src/main/java/com/netflix/conductor/client/http/PayloadStorage.java b/client/src/main/java/com/netflix/conductor/client/http/PayloadStorage.java index 0b05745f0..668e50047 100644 --- a/client/src/main/java/com/netflix/conductor/client/http/PayloadStorage.java +++ b/client/src/main/java/com/netflix/conductor/client/http/PayloadStorage.java @@ -1,5 +1,5 @@ /* - * Copyright 2020 Netflix, Inc. + * Copyright 2020 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/client/src/main/java/com/netflix/conductor/client/http/TaskClient.java b/client/src/main/java/com/netflix/conductor/client/http/TaskClient.java index d624ef0f6..35d48b2e3 100644 --- a/client/src/main/java/com/netflix/conductor/client/http/TaskClient.java +++ b/client/src/main/java/com/netflix/conductor/client/http/TaskClient.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/client/src/main/java/com/netflix/conductor/client/http/WorkflowClient.java b/client/src/main/java/com/netflix/conductor/client/http/WorkflowClient.java index 6bfa686bb..14deabff3 100644 --- a/client/src/main/java/com/netflix/conductor/client/http/WorkflowClient.java +++ b/client/src/main/java/com/netflix/conductor/client/http/WorkflowClient.java @@ -1,5 +1,5 @@ /* - * Copyright 2021 Netflix, Inc. + * Copyright 2021 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/client/src/main/java/com/netflix/conductor/client/telemetry/MetricsContainer.java b/client/src/main/java/com/netflix/conductor/client/telemetry/MetricsContainer.java index 7b9bb0ca3..d80349ff9 100644 --- a/client/src/main/java/com/netflix/conductor/client/telemetry/MetricsContainer.java +++ b/client/src/main/java/com/netflix/conductor/client/telemetry/MetricsContainer.java @@ -1,5 +1,5 @@ /* - * Copyright 2020 Netflix, Inc. + * Copyright 2020 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/client/src/main/java/com/netflix/conductor/client/worker/Worker.java b/client/src/main/java/com/netflix/conductor/client/worker/Worker.java index 9f07b151c..5b0ecc0b1 100644 --- a/client/src/main/java/com/netflix/conductor/client/worker/Worker.java +++ b/client/src/main/java/com/netflix/conductor/client/worker/Worker.java @@ -1,5 +1,5 @@ /* - * Copyright 2021 Netflix, Inc. + * Copyright 2021 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/client/src/test/groovy/com/netflix/conductor/client/http/ClientSpecification.groovy b/client/src/test/groovy/com/netflix/conductor/client/http/ClientSpecification.groovy index 5c4a5208d..c804f785c 100644 --- a/client/src/test/groovy/com/netflix/conductor/client/http/ClientSpecification.groovy +++ b/client/src/test/groovy/com/netflix/conductor/client/http/ClientSpecification.groovy @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/client/src/test/groovy/com/netflix/conductor/client/http/EventClientSpec.groovy b/client/src/test/groovy/com/netflix/conductor/client/http/EventClientSpec.groovy index f4f32a767..bb121c56d 100644 --- a/client/src/test/groovy/com/netflix/conductor/client/http/EventClientSpec.groovy +++ b/client/src/test/groovy/com/netflix/conductor/client/http/EventClientSpec.groovy @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/client/src/test/groovy/com/netflix/conductor/client/http/MetadataClientSpec.groovy b/client/src/test/groovy/com/netflix/conductor/client/http/MetadataClientSpec.groovy index d82acc509..13790d3fc 100644 --- a/client/src/test/groovy/com/netflix/conductor/client/http/MetadataClientSpec.groovy +++ b/client/src/test/groovy/com/netflix/conductor/client/http/MetadataClientSpec.groovy @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/client/src/test/groovy/com/netflix/conductor/client/http/TaskClientSpec.groovy b/client/src/test/groovy/com/netflix/conductor/client/http/TaskClientSpec.groovy index bf21d8107..2caba4490 100644 --- a/client/src/test/groovy/com/netflix/conductor/client/http/TaskClientSpec.groovy +++ b/client/src/test/groovy/com/netflix/conductor/client/http/TaskClientSpec.groovy @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/client/src/test/groovy/com/netflix/conductor/client/http/WorkflowClientSpec.groovy b/client/src/test/groovy/com/netflix/conductor/client/http/WorkflowClientSpec.groovy index 08ebfee83..b4f30aeb1 100644 --- a/client/src/test/groovy/com/netflix/conductor/client/http/WorkflowClientSpec.groovy +++ b/client/src/test/groovy/com/netflix/conductor/client/http/WorkflowClientSpec.groovy @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/client/src/test/java/com/netflix/conductor/client/automator/PollingSemaphoreTest.java b/client/src/test/java/com/netflix/conductor/client/automator/PollingSemaphoreTest.java index 38735b120..7bc7e7c3a 100644 --- a/client/src/test/java/com/netflix/conductor/client/automator/PollingSemaphoreTest.java +++ b/client/src/test/java/com/netflix/conductor/client/automator/PollingSemaphoreTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2020 Netflix, Inc. + * Copyright 2020 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/client/src/test/java/com/netflix/conductor/client/automator/TaskPollExecutorTest.java b/client/src/test/java/com/netflix/conductor/client/automator/TaskPollExecutorTest.java index 5bbe8ba24..60855bdae 100644 --- a/client/src/test/java/com/netflix/conductor/client/automator/TaskPollExecutorTest.java +++ b/client/src/test/java/com/netflix/conductor/client/automator/TaskPollExecutorTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/client/src/test/java/com/netflix/conductor/client/automator/TaskRunnerConfigurerTest.java b/client/src/test/java/com/netflix/conductor/client/automator/TaskRunnerConfigurerTest.java index d86ae76f1..cbd9df8a9 100644 --- a/client/src/test/java/com/netflix/conductor/client/automator/TaskRunnerConfigurerTest.java +++ b/client/src/test/java/com/netflix/conductor/client/automator/TaskRunnerConfigurerTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2020 Netflix, Inc. + * Copyright 2020 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/client/src/test/java/com/netflix/conductor/client/config/TestPropertyFactory.java b/client/src/test/java/com/netflix/conductor/client/config/TestPropertyFactory.java index 87b6f40e4..398738c59 100644 --- a/client/src/test/java/com/netflix/conductor/client/config/TestPropertyFactory.java +++ b/client/src/test/java/com/netflix/conductor/client/config/TestPropertyFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 2020 Netflix, Inc. + * Copyright 2020 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/client/src/test/java/com/netflix/conductor/client/sample/Main.java b/client/src/test/java/com/netflix/conductor/client/sample/Main.java index 6fbbb00d1..7a474b146 100644 --- a/client/src/test/java/com/netflix/conductor/client/sample/Main.java +++ b/client/src/test/java/com/netflix/conductor/client/sample/Main.java @@ -1,5 +1,5 @@ /* - * Copyright 2020 Netflix, Inc. + * Copyright 2020 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/client/src/test/java/com/netflix/conductor/client/sample/SampleWorker.java b/client/src/test/java/com/netflix/conductor/client/sample/SampleWorker.java index cc2cbda60..6073c3f90 100644 --- a/client/src/test/java/com/netflix/conductor/client/sample/SampleWorker.java +++ b/client/src/test/java/com/netflix/conductor/client/sample/SampleWorker.java @@ -1,5 +1,5 @@ /* - * Copyright 2020 Netflix, Inc. + * Copyright 2020 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/client/src/test/java/com/netflix/conductor/client/testing/AbstractWorkflowTests.java b/client/src/test/java/com/netflix/conductor/client/testing/AbstractWorkflowTests.java index 69703816d..c2afa03f3 100644 --- a/client/src/test/java/com/netflix/conductor/client/testing/AbstractWorkflowTests.java +++ b/client/src/test/java/com/netflix/conductor/client/testing/AbstractWorkflowTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2023 Netflix, Inc. + * Copyright 2023 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/client/src/test/java/com/netflix/conductor/client/testing/LoanWorkflowInput.java b/client/src/test/java/com/netflix/conductor/client/testing/LoanWorkflowInput.java index cb48576a6..cd73b1af4 100644 --- a/client/src/test/java/com/netflix/conductor/client/testing/LoanWorkflowInput.java +++ b/client/src/test/java/com/netflix/conductor/client/testing/LoanWorkflowInput.java @@ -1,5 +1,5 @@ /* - * Copyright 2023 Netflix, Inc. + * Copyright 2023 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/client/src/test/java/com/netflix/conductor/client/testing/LoanWorkflowTest.java b/client/src/test/java/com/netflix/conductor/client/testing/LoanWorkflowTest.java index df09964d8..84f876a1a 100644 --- a/client/src/test/java/com/netflix/conductor/client/testing/LoanWorkflowTest.java +++ b/client/src/test/java/com/netflix/conductor/client/testing/LoanWorkflowTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2023 Netflix, Inc. + * Copyright 2023 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/client/src/test/java/com/netflix/conductor/client/testing/RegressionTest.java b/client/src/test/java/com/netflix/conductor/client/testing/RegressionTest.java index 4b51a2df2..e67f83658 100644 --- a/client/src/test/java/com/netflix/conductor/client/testing/RegressionTest.java +++ b/client/src/test/java/com/netflix/conductor/client/testing/RegressionTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2023 Netflix, Inc. + * Copyright 2023 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/client/src/test/java/com/netflix/conductor/client/testing/SubWorkflowTest.java b/client/src/test/java/com/netflix/conductor/client/testing/SubWorkflowTest.java index 5994d8c1c..f01d3f921 100644 --- a/client/src/test/java/com/netflix/conductor/client/testing/SubWorkflowTest.java +++ b/client/src/test/java/com/netflix/conductor/client/testing/SubWorkflowTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2023 Netflix, Inc. + * Copyright 2023 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/client/src/test/java/com/netflix/conductor/client/worker/TestWorkflowTask.java b/client/src/test/java/com/netflix/conductor/client/worker/TestWorkflowTask.java index 62720e92f..32f7bcb76 100644 --- a/client/src/test/java/com/netflix/conductor/client/worker/TestWorkflowTask.java +++ b/client/src/test/java/com/netflix/conductor/client/worker/TestWorkflowTask.java @@ -1,5 +1,5 @@ /* - * Copyright 2020 Netflix, Inc. + * Copyright 2020 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/common-persistence/build.gradle b/common-persistence/build.gradle new file mode 100644 index 000000000..9d09a58ac --- /dev/null +++ b/common-persistence/build.gradle @@ -0,0 +1,10 @@ +dependencies { + + implementation project(':conductor-common') + implementation project(':conductor-core') + + implementation "com.fasterxml.jackson.core:jackson-databind" + implementation "com.fasterxml.jackson.core:jackson-core" + implementation "org.apache.commons:commons-lang3" + +} \ No newline at end of file diff --git a/common-persistence/src/test/java/com/netflix/conductor/dao/ExecutionDAOTest.java b/common-persistence/src/test/java/com/netflix/conductor/dao/ExecutionDAOTest.java new file mode 100644 index 000000000..fc4068706 --- /dev/null +++ b/common-persistence/src/test/java/com/netflix/conductor/dao/ExecutionDAOTest.java @@ -0,0 +1,440 @@ +/* + * Copyright 2023 Conductor Authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package com.netflix.conductor.dao; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.UUID; +import java.util.stream.Collectors; + +import org.apache.commons.lang3.builder.EqualsBuilder; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +import com.netflix.conductor.common.metadata.tasks.TaskDef; +import com.netflix.conductor.common.metadata.workflow.WorkflowDef; +import com.netflix.conductor.common.metadata.workflow.WorkflowTask; +import com.netflix.conductor.core.exception.NonTransientException; +import com.netflix.conductor.model.TaskModel; +import com.netflix.conductor.model.WorkflowModel; + +import static org.junit.Assert.*; + +public abstract class ExecutionDAOTest { + + protected abstract ExecutionDAO getExecutionDAO(); + + protected ConcurrentExecutionLimitDAO getConcurrentExecutionLimitDAO() { + return (ConcurrentExecutionLimitDAO) getExecutionDAO(); + } + + @Rule public ExpectedException expectedException = ExpectedException.none(); + + @Test + public void testTaskExceedsLimit() { + TaskDef taskDefinition = new TaskDef(); + taskDefinition.setName("task100"); + taskDefinition.setConcurrentExecLimit(1); + + WorkflowTask workflowTask = new WorkflowTask(); + workflowTask.setName("task1"); + workflowTask.setTaskDefinition(taskDefinition); + workflowTask.setTaskDefinition(taskDefinition); + + List tasks = new LinkedList<>(); + for (int i = 0; i < 15; i++) { + TaskModel task = new TaskModel(); + task.setScheduledTime(1L); + task.setSeq(i + 1); + task.setTaskId("t_" + i); + task.setWorkflowInstanceId("workflow_" + i); + task.setReferenceTaskName("task1"); + task.setTaskDefName("task100"); + tasks.add(task); + task.setStatus(TaskModel.Status.SCHEDULED); + task.setWorkflowTask(workflowTask); + } + + getExecutionDAO().createTasks(tasks); + assertFalse(getConcurrentExecutionLimitDAO().exceedsLimit(tasks.get(0))); + tasks.get(0).setStatus(TaskModel.Status.IN_PROGRESS); + getExecutionDAO().updateTask(tasks.get(0)); + + for (TaskModel task : tasks) { + assertTrue(getConcurrentExecutionLimitDAO().exceedsLimit(task)); + } + } + + @Test + public void testCreateTaskException() { + TaskModel task = new TaskModel(); + task.setScheduledTime(1L); + task.setSeq(1); + task.setTaskId(UUID.randomUUID().toString()); + task.setTaskDefName("task1"); + + expectedException.expect(NonTransientException.class); + expectedException.expectMessage("Workflow instance id cannot be null"); + getExecutionDAO().createTasks(Collections.singletonList(task)); + + task.setWorkflowInstanceId(UUID.randomUUID().toString()); + expectedException.expect(NonTransientException.class); + expectedException.expectMessage("Task reference name cannot be null"); + getExecutionDAO().createTasks(Collections.singletonList(task)); + } + + @Test + public void testCreateTaskException2() { + TaskModel task = new TaskModel(); + task.setScheduledTime(1L); + task.setSeq(1); + task.setTaskId(UUID.randomUUID().toString()); + task.setTaskDefName("task1"); + task.setWorkflowInstanceId(UUID.randomUUID().toString()); + + expectedException.expect(NonTransientException.class); + expectedException.expectMessage("Task reference name cannot be null"); + getExecutionDAO().createTasks(Collections.singletonList(task)); + } + + @Test + public void testTaskCreateDups() { + List tasks = new LinkedList<>(); + String workflowId = UUID.randomUUID().toString(); + + for (int i = 0; i < 3; i++) { + TaskModel task = new TaskModel(); + task.setScheduledTime(1L); + task.setSeq(i + 1); + task.setTaskId(workflowId + "_t" + i); + task.setReferenceTaskName("t" + i); + task.setRetryCount(0); + task.setWorkflowInstanceId(workflowId); + task.setTaskDefName("task" + i); + task.setStatus(TaskModel.Status.IN_PROGRESS); + tasks.add(task); + } + + // Let's insert a retried task + TaskModel task = new TaskModel(); + task.setScheduledTime(1L); + task.setSeq(1); + task.setTaskId(workflowId + "_t" + 2); + task.setReferenceTaskName("t" + 2); + task.setRetryCount(1); + task.setWorkflowInstanceId(workflowId); + task.setTaskDefName("task" + 2); + task.setStatus(TaskModel.Status.IN_PROGRESS); + tasks.add(task); + + // Duplicate task! + task = new TaskModel(); + task.setScheduledTime(1L); + task.setSeq(1); + task.setTaskId(workflowId + "_t" + 1); + task.setReferenceTaskName("t" + 1); + task.setRetryCount(0); + task.setWorkflowInstanceId(workflowId); + task.setTaskDefName("task" + 1); + task.setStatus(TaskModel.Status.IN_PROGRESS); + tasks.add(task); + + List created = getExecutionDAO().createTasks(tasks); + assertEquals(tasks.size() - 1, created.size()); // 1 less + + Set srcIds = + tasks.stream() + .map(t -> t.getReferenceTaskName() + "." + t.getRetryCount()) + .collect(Collectors.toSet()); + Set createdIds = + created.stream() + .map(t -> t.getReferenceTaskName() + "." + t.getRetryCount()) + .collect(Collectors.toSet()); + + assertEquals(srcIds, createdIds); + + List pending = getExecutionDAO().getPendingTasksByWorkflow("task0", workflowId); + assertNotNull(pending); + assertEquals(1, pending.size()); + assertTrue(EqualsBuilder.reflectionEquals(tasks.get(0), pending.get(0))); + + List found = getExecutionDAO().getTasks(tasks.get(0).getTaskDefName(), null, 1); + assertNotNull(found); + assertEquals(1, found.size()); + assertTrue(EqualsBuilder.reflectionEquals(tasks.get(0), found.get(0))); + } + + @Test + public void testTaskOps() { + List tasks = new LinkedList<>(); + String workflowId = UUID.randomUUID().toString(); + + for (int i = 0; i < 3; i++) { + TaskModel task = new TaskModel(); + task.setScheduledTime(1L); + task.setSeq(1); + task.setTaskId(workflowId + "_t" + i); + task.setReferenceTaskName("testTaskOps" + i); + task.setRetryCount(0); + task.setWorkflowInstanceId(workflowId); + task.setTaskDefName("testTaskOps" + i); + task.setStatus(TaskModel.Status.IN_PROGRESS); + tasks.add(task); + } + + for (int i = 0; i < 3; i++) { + TaskModel task = new TaskModel(); + task.setScheduledTime(1L); + task.setSeq(1); + task.setTaskId("x" + workflowId + "_t" + i); + task.setReferenceTaskName("testTaskOps" + i); + task.setRetryCount(0); + task.setWorkflowInstanceId("x" + workflowId); + task.setTaskDefName("testTaskOps" + i); + task.setStatus(TaskModel.Status.IN_PROGRESS); + getExecutionDAO().createTasks(Collections.singletonList(task)); + } + + List created = getExecutionDAO().createTasks(tasks); + assertEquals(tasks.size(), created.size()); + + List pending = + getExecutionDAO().getPendingTasksForTaskType(tasks.get(0).getTaskDefName()); + assertNotNull(pending); + assertEquals(2, pending.size()); + // Pending list can come in any order. finding the one we are looking for and then + // comparing + TaskModel matching = + pending.stream() + .filter(task -> task.getTaskId().equals(tasks.get(0).getTaskId())) + .findAny() + .get(); + assertTrue(EqualsBuilder.reflectionEquals(matching, tasks.get(0))); + + for (int i = 0; i < 3; i++) { + TaskModel found = getExecutionDAO().getTask(workflowId + "_t" + i); + assertNotNull(found); + found.getOutputData().put("updated", true); + found.setStatus(TaskModel.Status.COMPLETED); + getExecutionDAO().updateTask(found); + } + + List taskIds = + tasks.stream().map(TaskModel::getTaskId).collect(Collectors.toList()); + List found = getExecutionDAO().getTasks(taskIds); + assertEquals(taskIds.size(), found.size()); + found.forEach( + task -> { + assertTrue(task.getOutputData().containsKey("updated")); + assertEquals(true, task.getOutputData().get("updated")); + boolean removed = getExecutionDAO().removeTask(task.getTaskId()); + assertTrue(removed); + }); + + found = getExecutionDAO().getTasks(taskIds); + assertTrue(found.isEmpty()); + } + + @Test + public void testPending() { + WorkflowDef def = new WorkflowDef(); + def.setName("pending_count_test"); + + WorkflowModel workflow = createTestWorkflow(); + workflow.setWorkflowDefinition(def); + + List workflowIds = generateWorkflows(workflow, 10); + long count = getExecutionDAO().getPendingWorkflowCount(def.getName()); + assertEquals(10, count); + + for (int i = 0; i < 10; i++) { + getExecutionDAO().removeFromPendingWorkflow(def.getName(), workflowIds.get(i)); + } + + count = getExecutionDAO().getPendingWorkflowCount(def.getName()); + assertEquals(0, count); + } + + @Test + public void complexExecutionTest() { + WorkflowModel workflow = createTestWorkflow(); + int numTasks = workflow.getTasks().size(); + + String workflowId = getExecutionDAO().createWorkflow(workflow); + assertEquals(workflow.getWorkflowId(), workflowId); + + List created = getExecutionDAO().createTasks(workflow.getTasks()); + assertEquals(workflow.getTasks().size(), created.size()); + + WorkflowModel workflowWithTasks = + getExecutionDAO().getWorkflow(workflow.getWorkflowId(), true); + assertEquals(workflowId, workflowWithTasks.getWorkflowId()); + assertEquals(numTasks, workflowWithTasks.getTasks().size()); + + WorkflowModel found = getExecutionDAO().getWorkflow(workflowId, false); + assertTrue(found.getTasks().isEmpty()); + + workflow.getTasks().clear(); + assertEquals(workflow, found); + + workflow.getInput().put("updated", true); + getExecutionDAO().updateWorkflow(workflow); + found = getExecutionDAO().getWorkflow(workflowId); + assertNotNull(found); + assertTrue(found.getInput().containsKey("updated")); + assertEquals(true, found.getInput().get("updated")); + + List running = + getExecutionDAO() + .getRunningWorkflowIds( + workflow.getWorkflowName(), workflow.getWorkflowVersion()); + assertNotNull(running); + assertTrue(running.isEmpty()); + + workflow.setStatus(WorkflowModel.Status.RUNNING); + getExecutionDAO().updateWorkflow(workflow); + + running = + getExecutionDAO() + .getRunningWorkflowIds( + workflow.getWorkflowName(), workflow.getWorkflowVersion()); + assertNotNull(running); + assertEquals(1, running.size()); + assertEquals(workflow.getWorkflowId(), running.get(0)); + + List pending = + getExecutionDAO() + .getPendingWorkflowsByType( + workflow.getWorkflowName(), workflow.getWorkflowVersion()); + assertNotNull(pending); + assertEquals(1, pending.size()); + assertEquals(3, pending.get(0).getTasks().size()); + pending.get(0).getTasks().clear(); + assertEquals(workflow, pending.get(0)); + + workflow.setStatus(WorkflowModel.Status.COMPLETED); + getExecutionDAO().updateWorkflow(workflow); + running = + getExecutionDAO() + .getRunningWorkflowIds( + workflow.getWorkflowName(), workflow.getWorkflowVersion()); + assertNotNull(running); + assertTrue(running.isEmpty()); + + List bytime = + getExecutionDAO() + .getWorkflowsByType( + workflow.getWorkflowName(), + System.currentTimeMillis(), + System.currentTimeMillis() + 100); + assertNotNull(bytime); + assertTrue(bytime.isEmpty()); + + bytime = + getExecutionDAO() + .getWorkflowsByType( + workflow.getWorkflowName(), + workflow.getCreateTime() - 10, + workflow.getCreateTime() + 10); + assertNotNull(bytime); + assertEquals(1, bytime.size()); + } + + protected WorkflowModel createTestWorkflow() { + WorkflowDef def = new WorkflowDef(); + def.setName("Junit Workflow"); + def.setVersion(3); + def.setSchemaVersion(2); + + WorkflowModel workflow = new WorkflowModel(); + workflow.setWorkflowDefinition(def); + workflow.setCorrelationId("correlationX"); + workflow.setCreatedBy("junit_tester"); + workflow.setEndTime(200L); + + Map input = new HashMap<>(); + input.put("param1", "param1 value"); + input.put("param2", 100); + workflow.setInput(input); + + Map output = new HashMap<>(); + output.put("ouput1", "output 1 value"); + output.put("op2", 300); + workflow.setOutput(output); + + workflow.setOwnerApp("workflow"); + workflow.setParentWorkflowId("parentWorkflowId"); + workflow.setParentWorkflowTaskId("parentWFTaskId"); + workflow.setReasonForIncompletion("missing recipe"); + workflow.setReRunFromWorkflowId("re-run from id1"); + workflow.setCreateTime(90L); + workflow.setStatus(WorkflowModel.Status.FAILED); + workflow.setWorkflowId(UUID.randomUUID().toString()); + + List tasks = new LinkedList<>(); + + TaskModel task = new TaskModel(); + task.setScheduledTime(1L); + task.setSeq(1); + task.setTaskId(UUID.randomUUID().toString()); + task.setReferenceTaskName("t1"); + task.setWorkflowInstanceId(workflow.getWorkflowId()); + task.setTaskDefName("task1"); + + TaskModel task2 = new TaskModel(); + task2.setScheduledTime(2L); + task2.setSeq(2); + task2.setTaskId(UUID.randomUUID().toString()); + task2.setReferenceTaskName("t2"); + task2.setWorkflowInstanceId(workflow.getWorkflowId()); + task2.setTaskDefName("task2"); + + TaskModel task3 = new TaskModel(); + task3.setScheduledTime(2L); + task3.setSeq(3); + task3.setTaskId(UUID.randomUUID().toString()); + task3.setReferenceTaskName("t3"); + task3.setWorkflowInstanceId(workflow.getWorkflowId()); + task3.setTaskDefName("task3"); + + tasks.add(task); + tasks.add(task2); + tasks.add(task3); + + workflow.setTasks(tasks); + + workflow.setUpdatedBy("junit_tester"); + workflow.setUpdatedTime(800L); + + return workflow; + } + + protected List generateWorkflows(WorkflowModel base, int count) { + List workflowIds = new ArrayList<>(); + for (int i = 0; i < count; i++) { + String workflowId = UUID.randomUUID().toString(); + base.setWorkflowId(workflowId); + base.setCorrelationId("corr001"); + base.setStatus(WorkflowModel.Status.RUNNING); + getExecutionDAO().createWorkflow(base); + workflowIds.add(workflowId); + } + return workflowIds; + } +} diff --git a/common-persistence/src/test/java/com/netflix/conductor/dao/TestBase.java b/common-persistence/src/test/java/com/netflix/conductor/dao/TestBase.java new file mode 100644 index 000000000..7d1d14106 --- /dev/null +++ b/common-persistence/src/test/java/com/netflix/conductor/dao/TestBase.java @@ -0,0 +1,15 @@ +/* + * Copyright 2023 Conductor Authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package com.netflix.conductor.dao; + +public class TestBase {} diff --git a/common/build.gradle b/common/build.gradle index 5f20d89b8..8332cb312 100644 --- a/common/build.gradle +++ b/common/build.gradle @@ -9,7 +9,7 @@ dependencies { compileOnly 'org.springframework.boot:spring-boot-starter' compileOnly 'org.springframework.boot:spring-boot-starter-validation' - compileOnly "org.springdoc:springdoc-openapi-ui:${revOpenapi}" + compileOnly "org.springdoc:springdoc-openapi-starter-webmvc-ui:${revSpringDoc}" implementation "org.apache.commons:commons-lang3" @@ -23,10 +23,11 @@ dependencies { implementation "com.fasterxml.jackson.module:jackson-module-afterburner:${revFasterXml}" testImplementation 'org.springframework.boot:spring-boot-starter-validation' + testImplementation "org.springdoc:springdoc-openapi-starter-webmvc-ui:${revSpringDoc}" } /* - * Copyright 2021 Netflix, Inc. + * Copyright 2023 Conductor authors *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/common/dependencies.lock b/common/dependencies.lock deleted file mode 100644 index b046f5bb4..000000000 --- a/common/dependencies.lock +++ /dev/null @@ -1,574 +0,0 @@ -{ - "annotationProcessor": { - "org.springframework.boot:spring-boot-configuration-processor": { - "locked": "2.7.16" - } - }, - "annotationsProcessorCodegen": { - "com.fasterxml.jackson.core:jackson-annotations": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-annotations-processor" - ], - "locked": "2.13.5" - }, - "com.fasterxml.jackson.core:jackson-core": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-annotations-processor" - ], - "locked": "2.13.5" - }, - "com.fasterxml.jackson.core:jackson-databind": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-annotations-processor" - ], - "locked": "2.13.5" - }, - "com.fasterxml.jackson.dataformat:jackson-dataformat-cbor": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-annotations-processor" - ], - "locked": "2.13.5" - }, - "com.fasterxml.jackson.dataformat:jackson-dataformat-smile": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-annotations-processor" - ], - "locked": "2.13.5" - }, - "com.fasterxml.jackson.dataformat:jackson-dataformat-yaml": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-annotations-processor" - ], - "locked": "2.13.5" - }, - "com.fasterxml.jackson.datatype:jackson-datatype-jdk8": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-annotations-processor" - ], - "locked": "2.13.5" - }, - "com.fasterxml.jackson.datatype:jackson-datatype-joda": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-annotations-processor" - ], - "locked": "2.13.5" - }, - "com.fasterxml.jackson.datatype:jackson-datatype-jsr310": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-annotations-processor" - ], - "locked": "2.13.5" - }, - "com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-annotations-processor" - ], - "locked": "2.13.5" - }, - "com.fasterxml.jackson.module:jackson-module-afterburner": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-annotations-processor" - ], - "locked": "2.13.5" - }, - "com.github.jknack:handlebars": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations-processor" - ], - "locked": "4.3.1" - }, - "com.google.guava:guava": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations-processor" - ], - "locked": "32.1.2-jre" - }, - "com.google.protobuf:protobuf-java": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations-processor" - ], - "locked": "3.21.12" - }, - "com.netflix.conductor:conductor-annotations": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations-processor" - ], - "project": true - }, - "com.netflix.conductor:conductor-annotations-processor": { - "project": true - }, - "com.squareup:javapoet": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations-processor" - ], - "locked": "1.13.0" - }, - "javax.annotation:javax.annotation-api": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations-processor" - ], - "locked": "1.3.2" - }, - "org.apache.logging.log4j:log4j-api": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-annotations-processor" - ], - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-core": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-annotations-processor" - ], - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-jul": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-annotations-processor" - ], - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-slf4j-impl": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-annotations-processor" - ], - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-web": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-annotations-processor" - ], - "locked": "2.17.2" - }, - "org.yaml:snakeyaml": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-annotations-processor" - ], - "locked": "1.30" - } - }, - "compileClasspath": { - "com.fasterxml.jackson.core:jackson-annotations": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.core:jackson-core": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.core:jackson-databind": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.dataformat:jackson-dataformat-cbor": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.dataformat:jackson-dataformat-smile": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.dataformat:jackson-dataformat-yaml": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.datatype:jackson-datatype-jdk8": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.datatype:jackson-datatype-joda": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.datatype:jackson-datatype-jsr310": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.module:jackson-module-afterburner": { - "locked": "2.15.0" - }, - "com.google.protobuf:protobuf-java": { - "locked": "3.24.3" - }, - "com.netflix.conductor:conductor-annotations": { - "project": true - }, - "org.apache.bval:bval-jsr": { - "locked": "2.0.6" - }, - "org.apache.commons:commons-lang3": { - "locked": "3.12.0" - }, - "org.apache.logging.log4j:log4j-api": { - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-core": { - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-jul": { - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-slf4j-impl": { - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-web": { - "locked": "2.17.2" - }, - "org.springdoc:springdoc-openapi-ui": { - "locked": "1.6.15" - }, - "org.springframework.boot:spring-boot-starter": { - "locked": "2.7.16" - }, - "org.springframework.boot:spring-boot-starter-validation": { - "locked": "2.7.16" - }, - "org.yaml:snakeyaml": { - "locked": "2.0" - } - }, - "runtimeClasspath": { - "com.fasterxml.jackson.core:jackson-annotations": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.core:jackson-core": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.core:jackson-databind": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.dataformat:jackson-dataformat-cbor": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.dataformat:jackson-dataformat-smile": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.dataformat:jackson-dataformat-yaml": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.datatype:jackson-datatype-jdk8": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.datatype:jackson-datatype-joda": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.datatype:jackson-datatype-jsr310": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.module:jackson-module-afterburner": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations" - ], - "locked": "2.15.0" - }, - "com.google.protobuf:protobuf-java": { - "locked": "3.24.3" - }, - "com.netflix.conductor:conductor-annotations": { - "project": true - }, - "org.apache.bval:bval-jsr": { - "locked": "2.0.6" - }, - "org.apache.commons:commons-lang3": { - "locked": "3.12.0" - }, - "org.apache.logging.log4j:log4j-api": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations" - ], - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-core": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations" - ], - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-jul": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations" - ], - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-slf4j-impl": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations" - ], - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-web": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations" - ], - "locked": "2.17.2" - }, - "org.yaml:snakeyaml": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations" - ], - "locked": "2.0" - } - }, - "testCompileClasspath": { - "com.fasterxml.jackson.core:jackson-annotations": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.core:jackson-core": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.core:jackson-databind": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.dataformat:jackson-dataformat-cbor": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.dataformat:jackson-dataformat-smile": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.dataformat:jackson-dataformat-yaml": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.datatype:jackson-datatype-jdk8": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.datatype:jackson-datatype-joda": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.datatype:jackson-datatype-jsr310": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.module:jackson-module-afterburner": { - "locked": "2.15.0" - }, - "com.google.protobuf:protobuf-java": { - "locked": "3.24.3" - }, - "com.netflix.conductor:conductor-annotations": { - "project": true - }, - "junit:junit": { - "locked": "4.13.2" - }, - "net.java.dev.jna:jna": { - "locked": "5.13.0" - }, - "org.apache.bval:bval-jsr": { - "locked": "2.0.6" - }, - "org.apache.commons:commons-lang3": { - "locked": "3.12.0" - }, - "org.apache.logging.log4j:log4j-api": { - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-core": { - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-jul": { - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-slf4j-impl": { - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-web": { - "locked": "2.17.2" - }, - "org.junit.vintage:junit-vintage-engine": { - "locked": "5.8.2" - }, - "org.springframework.boot:spring-boot-starter-log4j2": { - "locked": "2.7.16" - }, - "org.springframework.boot:spring-boot-starter-test": { - "locked": "2.7.16" - }, - "org.springframework.boot:spring-boot-starter-validation": { - "locked": "2.7.16" - }, - "org.yaml:snakeyaml": { - "locked": "2.0" - } - }, - "testRuntimeClasspath": { - "com.fasterxml.jackson.core:jackson-annotations": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.core:jackson-core": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.core:jackson-databind": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.dataformat:jackson-dataformat-cbor": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.dataformat:jackson-dataformat-smile": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.dataformat:jackson-dataformat-yaml": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.datatype:jackson-datatype-jdk8": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.datatype:jackson-datatype-joda": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.datatype:jackson-datatype-jsr310": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.module:jackson-module-afterburner": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations" - ], - "locked": "2.15.0" - }, - "com.google.protobuf:protobuf-java": { - "locked": "3.24.3" - }, - "com.netflix.conductor:conductor-annotations": { - "project": true - }, - "junit:junit": { - "locked": "4.13.2" - }, - "net.java.dev.jna:jna": { - "locked": "5.13.0" - }, - "org.apache.bval:bval-jsr": { - "locked": "2.0.6" - }, - "org.apache.commons:commons-lang3": { - "locked": "3.12.0" - }, - "org.apache.logging.log4j:log4j-api": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations" - ], - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-core": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations" - ], - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-jul": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations" - ], - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-slf4j-impl": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations" - ], - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-web": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations" - ], - "locked": "2.17.2" - }, - "org.junit.vintage:junit-vintage-engine": { - "locked": "5.8.2" - }, - "org.springframework.boot:spring-boot-starter-log4j2": { - "locked": "2.7.16" - }, - "org.springframework.boot:spring-boot-starter-test": { - "locked": "2.7.16" - }, - "org.springframework.boot:spring-boot-starter-validation": { - "locked": "2.7.16" - }, - "org.yaml:snakeyaml": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations" - ], - "locked": "2.0" - } - } -} \ No newline at end of file diff --git a/common/src/main/java/com/netflix/conductor/annotations/protogen/ProtoEnum.java b/common/src/main/java/com/netflix/conductor/annotations/protogen/ProtoEnum.java new file mode 100644 index 000000000..c07e679f7 --- /dev/null +++ b/common/src/main/java/com/netflix/conductor/annotations/protogen/ProtoEnum.java @@ -0,0 +1,26 @@ +/* + * Copyright 2022 Conductor Authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package com.netflix.conductor.annotations.protogen; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * ProtoEnum annotates an enum type that will be exposed via the GRPC API as a native Protocol + * Buffers enum. + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +public @interface ProtoEnum {} diff --git a/common/src/main/java/com/netflix/conductor/annotations/protogen/ProtoField.java b/common/src/main/java/com/netflix/conductor/annotations/protogen/ProtoField.java new file mode 100644 index 000000000..a61bb5ea1 --- /dev/null +++ b/common/src/main/java/com/netflix/conductor/annotations/protogen/ProtoField.java @@ -0,0 +1,36 @@ +/* + * Copyright 2022 Conductor Authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package com.netflix.conductor.annotations.protogen; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * ProtoField annotates a field inside an struct with metadata on how to expose it on its + * corresponding Protocol Buffers struct. For a field to be exposed in a ProtoBuf struct, the + * containing struct must also be annotated with a {@link ProtoMessage} or {@link ProtoEnum} tag. + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +public @interface ProtoField { + /** + * Mandatory. Sets the Protocol Buffer ID for this specific field. Once a field has been + * annotated with a given ID, the ID can never change to a different value or the resulting + * Protocol Buffer struct will not be backwards compatible. + * + * @return the numeric ID for the field + */ + int id(); +} diff --git a/common/src/main/java/com/netflix/conductor/annotations/protogen/ProtoMessage.java b/common/src/main/java/com/netflix/conductor/annotations/protogen/ProtoMessage.java new file mode 100644 index 000000000..45fa884f9 --- /dev/null +++ b/common/src/main/java/com/netflix/conductor/annotations/protogen/ProtoMessage.java @@ -0,0 +1,51 @@ +/* + * Copyright 2022 Conductor Authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package com.netflix.conductor.annotations.protogen; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * ProtoMessage annotates a given Java class so it becomes exposed via the GRPC API as a native + * Protocol Buffers struct. The annotated class must be a POJO. + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +public @interface ProtoMessage { + /** + * Sets whether the generated mapping code will contain a helper to translate the POJO for this + * class into the equivalent ProtoBuf object. + * + * @return whether this class will generate a mapper to ProtoBuf objects + */ + boolean toProto() default true; + + /** + * Sets whether the generated mapping code will contain a helper to translate the ProtoBuf + * object for this class into the equivalent POJO. + * + * @return whether this class will generate a mapper from ProtoBuf objects + */ + boolean fromProto() default true; + + /** + * Sets whether this is a wrapper class that will be used to encapsulate complex nested type + * interfaces. Wrapper classes are not directly exposed by the ProtoBuf API and must be mapped + * manually. + * + * @return whether this is a wrapper class + */ + boolean wrapper() default false; +} diff --git a/common/src/main/java/com/netflix/conductor/common/config/ObjectMapperBuilderConfiguration.java b/common/src/main/java/com/netflix/conductor/common/config/ObjectMapperBuilderConfiguration.java index a281edb34..40b781eab 100644 --- a/common/src/main/java/com/netflix/conductor/common/config/ObjectMapperBuilderConfiguration.java +++ b/common/src/main/java/com/netflix/conductor/common/config/ObjectMapperBuilderConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2021 Netflix, Inc. + * Copyright 2021 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/common/src/main/java/com/netflix/conductor/common/config/ObjectMapperConfiguration.java b/common/src/main/java/com/netflix/conductor/common/config/ObjectMapperConfiguration.java index ffcb71945..9d698cb1b 100644 --- a/common/src/main/java/com/netflix/conductor/common/config/ObjectMapperConfiguration.java +++ b/common/src/main/java/com/netflix/conductor/common/config/ObjectMapperConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2021 Netflix, Inc. + * Copyright 2021 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at @@ -12,13 +12,12 @@ */ package com.netflix.conductor.common.config; -import javax.annotation.PostConstruct; - import org.springframework.context.annotation.Configuration; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.module.afterburner.AfterburnerModule; +import jakarta.annotation.PostConstruct; @Configuration public class ObjectMapperConfiguration { diff --git a/common/src/main/java/com/netflix/conductor/common/config/ObjectMapperProvider.java b/common/src/main/java/com/netflix/conductor/common/config/ObjectMapperProvider.java index 43398df79..5e3a5562c 100644 --- a/common/src/main/java/com/netflix/conductor/common/config/ObjectMapperProvider.java +++ b/common/src/main/java/com/netflix/conductor/common/config/ObjectMapperProvider.java @@ -1,5 +1,5 @@ /* - * Copyright 2021 Netflix, Inc. + * Copyright 2021 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at @@ -17,6 +17,8 @@ import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import com.fasterxml.jackson.module.afterburner.AfterburnerModule; /** @@ -26,6 +28,8 @@ */ public class ObjectMapperProvider { + private static final ObjectMapper objectMapper = _getObjectMapper(); + /** * The customizations in this method are configured using {@link * org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration} @@ -39,6 +43,10 @@ public class ObjectMapperProvider { * @see org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration */ public ObjectMapper getObjectMapper() { + return objectMapper; + } + + private static ObjectMapper _getObjectMapper() { final ObjectMapper objectMapper = new ObjectMapper(); objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); objectMapper.configure(DeserializationFeature.FAIL_ON_IGNORED_PROPERTIES, false); @@ -46,7 +54,9 @@ public ObjectMapper getObjectMapper() { objectMapper.setDefaultPropertyInclusion( JsonInclude.Value.construct( JsonInclude.Include.NON_NULL, JsonInclude.Include.ALWAYS)); + objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false); objectMapper.registerModule(new JsonProtoModule()); + objectMapper.registerModule(new JavaTimeModule()); objectMapper.registerModule(new AfterburnerModule()); return objectMapper; } diff --git a/common/src/main/java/com/netflix/conductor/common/constraints/NoSemiColonConstraint.java b/common/src/main/java/com/netflix/conductor/common/constraints/NoSemiColonConstraint.java index 3bd402013..b3482c979 100644 --- a/common/src/main/java/com/netflix/conductor/common/constraints/NoSemiColonConstraint.java +++ b/common/src/main/java/com/netflix/conductor/common/constraints/NoSemiColonConstraint.java @@ -1,5 +1,5 @@ /* - * Copyright 2020 Netflix, Inc. + * Copyright 2020 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at @@ -17,13 +17,13 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; -import javax.validation.Constraint; -import javax.validation.ConstraintValidator; -import javax.validation.ConstraintValidatorContext; -import javax.validation.Payload; - import org.apache.commons.lang3.StringUtils; +import jakarta.validation.Constraint; +import jakarta.validation.ConstraintValidator; +import jakarta.validation.ConstraintValidatorContext; +import jakarta.validation.Payload; + import static java.lang.annotation.ElementType.FIELD; import static java.lang.annotation.ElementType.PARAMETER; diff --git a/common/src/main/java/com/netflix/conductor/common/constraints/OwnerEmailMandatoryConstraint.java b/common/src/main/java/com/netflix/conductor/common/constraints/OwnerEmailMandatoryConstraint.java index 55347529d..297d61442 100644 --- a/common/src/main/java/com/netflix/conductor/common/constraints/OwnerEmailMandatoryConstraint.java +++ b/common/src/main/java/com/netflix/conductor/common/constraints/OwnerEmailMandatoryConstraint.java @@ -1,5 +1,5 @@ /* - * Copyright 2020 Netflix, Inc. + * Copyright 2020 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at @@ -17,13 +17,13 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; -import javax.validation.Constraint; -import javax.validation.ConstraintValidator; -import javax.validation.ConstraintValidatorContext; -import javax.validation.Payload; - import org.apache.commons.lang3.StringUtils; +import jakarta.validation.Constraint; +import jakarta.validation.ConstraintValidator; +import jakarta.validation.ConstraintValidatorContext; +import jakarta.validation.Payload; + import static java.lang.annotation.ElementType.FIELD; import static java.lang.annotation.ElementType.TYPE; diff --git a/common/src/main/java/com/netflix/conductor/common/constraints/TaskReferenceNameUniqueConstraint.java b/common/src/main/java/com/netflix/conductor/common/constraints/TaskReferenceNameUniqueConstraint.java index 24f0ff433..3d325f577 100644 --- a/common/src/main/java/com/netflix/conductor/common/constraints/TaskReferenceNameUniqueConstraint.java +++ b/common/src/main/java/com/netflix/conductor/common/constraints/TaskReferenceNameUniqueConstraint.java @@ -1,5 +1,5 @@ /* - * Copyright 2020 Netflix, Inc. + * Copyright 2020 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at @@ -19,17 +19,17 @@ import java.util.HashMap; import java.util.List; -import javax.validation.Constraint; -import javax.validation.ConstraintValidator; -import javax.validation.ConstraintValidatorContext; -import javax.validation.Payload; - import org.apache.commons.lang3.mutable.MutableBoolean; import com.netflix.conductor.common.metadata.workflow.WorkflowDef; import com.netflix.conductor.common.metadata.workflow.WorkflowTask; import com.netflix.conductor.common.utils.ConstraintParamUtil; +import jakarta.validation.Constraint; +import jakarta.validation.ConstraintValidator; +import jakarta.validation.ConstraintValidatorContext; +import jakarta.validation.Payload; + import static java.lang.annotation.ElementType.TYPE; /** diff --git a/common/src/main/java/com/netflix/conductor/common/constraints/TaskTimeoutConstraint.java b/common/src/main/java/com/netflix/conductor/common/constraints/TaskTimeoutConstraint.java index 56525c7b5..a9e6576f0 100644 --- a/common/src/main/java/com/netflix/conductor/common/constraints/TaskTimeoutConstraint.java +++ b/common/src/main/java/com/netflix/conductor/common/constraints/TaskTimeoutConstraint.java @@ -1,5 +1,5 @@ /* - * Copyright 2020 Netflix, Inc. + * Copyright 2020 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at @@ -17,13 +17,13 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; -import javax.validation.Constraint; -import javax.validation.ConstraintValidator; -import javax.validation.ConstraintValidatorContext; -import javax.validation.Payload; - import com.netflix.conductor.common.metadata.tasks.TaskDef; +import jakarta.validation.Constraint; +import jakarta.validation.ConstraintValidator; +import jakarta.validation.ConstraintValidatorContext; +import jakarta.validation.Payload; + import static java.lang.annotation.ElementType.TYPE; /** diff --git a/common/src/main/java/com/netflix/conductor/common/jackson/JsonProtoModule.java b/common/src/main/java/com/netflix/conductor/common/jackson/JsonProtoModule.java index 29bb5e11d..b109e8ea9 100644 --- a/common/src/main/java/com/netflix/conductor/common/jackson/JsonProtoModule.java +++ b/common/src/main/java/com/netflix/conductor/common/jackson/JsonProtoModule.java @@ -1,5 +1,5 @@ /* - * Copyright 2021 Netflix, Inc. + * Copyright 2021 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/common/src/main/java/com/netflix/conductor/common/metadata/Auditable.java b/common/src/main/java/com/netflix/conductor/common/metadata/Auditable.java index 01f229480..bef2e1792 100644 --- a/common/src/main/java/com/netflix/conductor/common/metadata/Auditable.java +++ b/common/src/main/java/com/netflix/conductor/common/metadata/Auditable.java @@ -1,5 +1,5 @@ /* - * Copyright 2020 Netflix, Inc. + * Copyright 2020 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at @@ -42,7 +42,7 @@ public void setOwnerApp(String ownerApp) { * @return the createTime */ public Long getCreateTime() { - return createTime; + return createTime == null ? 0 : createTime; } /** @@ -56,7 +56,7 @@ public void setCreateTime(Long createTime) { * @return the updateTime */ public Long getUpdateTime() { - return updateTime; + return updateTime == null ? 0 : updateTime; } /** diff --git a/common/src/main/java/com/netflix/conductor/common/metadata/BaseDef.java b/common/src/main/java/com/netflix/conductor/common/metadata/BaseDef.java index d638d2d32..fac1d1047 100644 --- a/common/src/main/java/com/netflix/conductor/common/metadata/BaseDef.java +++ b/common/src/main/java/com/netflix/conductor/common/metadata/BaseDef.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at @@ -22,6 +22,7 @@ * A base class for {@link com.netflix.conductor.common.metadata.workflow.WorkflowDef} and {@link * com.netflix.conductor.common.metadata.tasks.TaskDef}. */ +@Deprecated public abstract class BaseDef extends Auditable { private final Map accessPolicy = new EnumMap<>(Permission.class); diff --git a/common/src/main/java/com/netflix/conductor/common/metadata/SchemaDef.java b/common/src/main/java/com/netflix/conductor/common/metadata/SchemaDef.java new file mode 100644 index 000000000..5d8b80bbf --- /dev/null +++ b/common/src/main/java/com/netflix/conductor/common/metadata/SchemaDef.java @@ -0,0 +1,62 @@ +/* + * Copyright 2024 Conductor Authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package com.netflix.conductor.common.metadata; + +import java.util.Map; + +import com.netflix.conductor.annotations.protogen.ProtoEnum; +import com.netflix.conductor.annotations.protogen.ProtoField; +import com.netflix.conductor.annotations.protogen.ProtoMessage; + +import jakarta.validation.constraints.NotNull; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +@EqualsAndHashCode(callSuper = true) +@Builder +@Data +@NoArgsConstructor +@AllArgsConstructor +@ProtoMessage +public class SchemaDef extends Auditable { + + @ProtoEnum + public enum Type { + JSON, + AVRO, + PROTOBUF + } + + @ProtoField(id = 1) + @NotNull + private String name; + + @ProtoField(id = 2) + @NotNull + @Builder.Default + private int version = 1; + + @ProtoField(id = 3) + @NotNull + private Type type; + + // Schema definition stored here + private Map data; + + // Externalized schema definition (eg. via AVRO, Protobuf registry) + // If using Orkes Schema registry, this points to the name of the schema in the registry + private String externalRef; +} diff --git a/common/src/main/java/com/netflix/conductor/common/metadata/acl/Permission.java b/common/src/main/java/com/netflix/conductor/common/metadata/acl/Permission.java index 26736f77e..a87c89953 100644 --- a/common/src/main/java/com/netflix/conductor/common/metadata/acl/Permission.java +++ b/common/src/main/java/com/netflix/conductor/common/metadata/acl/Permission.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at @@ -15,6 +15,7 @@ import com.netflix.conductor.annotations.protogen.ProtoEnum; @ProtoEnum +@Deprecated public enum Permission { OWNER, OPERATOR diff --git a/common/src/main/java/com/netflix/conductor/common/metadata/events/EventExecution.java b/common/src/main/java/com/netflix/conductor/common/metadata/events/EventExecution.java index d6a2065e6..fd5310ac5 100644 --- a/common/src/main/java/com/netflix/conductor/common/metadata/events/EventExecution.java +++ b/common/src/main/java/com/netflix/conductor/common/metadata/events/EventExecution.java @@ -1,5 +1,5 @@ /* - * Copyright 2020 Netflix, Inc. + * Copyright 2020 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/common/src/main/java/com/netflix/conductor/common/metadata/events/EventHandler.java b/common/src/main/java/com/netflix/conductor/common/metadata/events/EventHandler.java index 77dda4c1e..56817315a 100644 --- a/common/src/main/java/com/netflix/conductor/common/metadata/events/EventHandler.java +++ b/common/src/main/java/com/netflix/conductor/common/metadata/events/EventHandler.java @@ -1,5 +1,5 @@ /* - * Copyright 2020 Netflix, Inc. + * Copyright 2020 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at @@ -17,16 +17,15 @@ import java.util.List; import java.util.Map; -import javax.validation.Valid; -import javax.validation.constraints.NotEmpty; -import javax.validation.constraints.NotNull; - import com.netflix.conductor.annotations.protogen.ProtoEnum; import com.netflix.conductor.annotations.protogen.ProtoField; import com.netflix.conductor.annotations.protogen.ProtoMessage; import com.google.protobuf.Any; import io.swagger.v3.oas.annotations.Hidden; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; /** Defines an event handler */ @ProtoMessage @@ -147,7 +146,9 @@ public static class Action { public enum Type { start_workflow, complete_task, - fail_task + fail_task, + terminate_workflow, + update_workflow_variables } @ProtoField(id = 1) @@ -165,6 +166,12 @@ public enum Type { @ProtoField(id = 5) private boolean expandInlineJSON; + @ProtoField(id = 6) + private TerminateWorkflow terminate_workflow; + + @ProtoField(id = 7) + private UpdateWorkflowVariables update_workflow_variables; + /** * @return the action */ @@ -235,6 +242,35 @@ public void setExpandInlineJSON(boolean expandInlineJSON) { public boolean isExpandInlineJSON() { return expandInlineJSON; } + + /** + * @return the terminate_workflow + */ + public TerminateWorkflow getTerminate_workflow() { + return terminate_workflow; + } + + /** + * @param terminate_workflow the terminate_workflow to set + */ + public void setTerminate_workflow(TerminateWorkflow terminate_workflow) { + this.terminate_workflow = terminate_workflow; + } + + /** + * @return the update_workflow_variables + */ + public UpdateWorkflowVariables getUpdate_workflow_variables() { + return update_workflow_variables; + } + + /** + * @param update_workflow_variables the update_workflow_variables to set + */ + public void setUpdate_workflow_variables( + UpdateWorkflowVariables update_workflow_variables) { + this.update_workflow_variables = update_workflow_variables; + } } @ProtoMessage @@ -415,4 +451,97 @@ public void setTaskToDomain(Map taskToDomain) { this.taskToDomain = taskToDomain; } } + + @ProtoMessage + public static class TerminateWorkflow { + + @ProtoField(id = 1) + private String workflowId; + + @ProtoField(id = 2) + private String terminationReason; + + /** + * @return the workflowId + */ + public String getWorkflowId() { + return workflowId; + } + + /** + * @param workflowId the workflowId to set + */ + public void setWorkflowId(String workflowId) { + this.workflowId = workflowId; + } + + /** + * @return the reasonForTermination + */ + public String getTerminationReason() { + return terminationReason; + } + + /** + * @param terminationReason the reasonForTermination to set + */ + public void setTerminationReason(String terminationReason) { + this.terminationReason = terminationReason; + } + } + + @ProtoMessage + public static class UpdateWorkflowVariables { + + @ProtoField(id = 1) + private String workflowId; + + @ProtoField(id = 2) + private Map variables; + + @ProtoField(id = 3) + private Boolean appendArray; + + /** + * @return the workflowId + */ + public String getWorkflowId() { + return workflowId; + } + + /** + * @param workflowId the workflowId to set + */ + public void setWorkflowId(String workflowId) { + this.workflowId = workflowId; + } + + /** + * @return the variables + */ + public Map getVariables() { + return variables; + } + + /** + * @param variables the variables to set + */ + public void setVariables(Map variables) { + this.variables = variables; + } + + /** + * @return appendArray + */ + public Boolean isAppendArray() { + return appendArray; + } + + /** + * @param appendArray the appendArray to set + */ + public void setAppendArray(Boolean appendArray) { + this.appendArray = appendArray; + } + } } diff --git a/common/src/main/java/com/netflix/conductor/common/metadata/tasks/PollData.java b/common/src/main/java/com/netflix/conductor/common/metadata/tasks/PollData.java index b058e2cd4..f094fb20a 100644 --- a/common/src/main/java/com/netflix/conductor/common/metadata/tasks/PollData.java +++ b/common/src/main/java/com/netflix/conductor/common/metadata/tasks/PollData.java @@ -1,5 +1,5 @@ /* - * Copyright 2020 Netflix, Inc. + * Copyright 2020 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/common/src/main/java/com/netflix/conductor/common/metadata/tasks/Task.java b/common/src/main/java/com/netflix/conductor/common/metadata/tasks/Task.java index f51016340..495ff06a9 100644 --- a/common/src/main/java/com/netflix/conductor/common/metadata/tasks/Task.java +++ b/common/src/main/java/com/netflix/conductor/common/metadata/tasks/Task.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at @@ -202,6 +202,9 @@ public boolean isRetriable() { @ProtoField(id = 42) private boolean subworkflowChanged; + // If the task is an event associated with a parent task, the id of the parent task + private String parentTaskId; + public Task() {} /** @@ -754,6 +757,14 @@ public void setSubWorkflowId(String subWorkflowId) { } } + public String getParentTaskId() { + return parentTaskId; + } + + public void setParentTaskId(String parentTaskId) { + this.parentTaskId = parentTaskId; + } + public Task copy() { Task copy = new Task(); copy.setCallbackAfterSeconds(callbackAfterSeconds); @@ -786,7 +797,7 @@ public Task copy() { copy.setIsolationGroupId(isolationGroupId); copy.setSubWorkflowId(getSubWorkflowId()); copy.setSubworkflowChanged(subworkflowChanged); - + copy.setParentTaskId(parentTaskId); return copy; } @@ -807,7 +818,7 @@ public Task deepCopy() { deepCopy.setWorkerId(workerId); deepCopy.setReasonForIncompletion(reasonForIncompletion); deepCopy.setSeq(seq); - + deepCopy.setParentTaskId(parentTaskId); return deepCopy; } @@ -961,7 +972,8 @@ && getWorkflowPriority() == task.getWorkflowPriority() getExternalOutputPayloadStoragePath(), task.getExternalOutputPayloadStoragePath()) && Objects.equals(getIsolationGroupId(), task.getIsolationGroupId()) - && Objects.equals(getExecutionNameSpace(), task.getExecutionNameSpace()); + && Objects.equals(getExecutionNameSpace(), task.getExecutionNameSpace()) + && Objects.equals(getParentTaskId(), task.getParentTaskId()); } @Override @@ -1003,6 +1015,7 @@ public int hashCode() { getExternalInputPayloadStoragePath(), getExternalOutputPayloadStoragePath(), getIsolationGroupId(), - getExecutionNameSpace()); + getExecutionNameSpace(), + getParentTaskId()); } } diff --git a/common/src/main/java/com/netflix/conductor/common/metadata/tasks/TaskDef.java b/common/src/main/java/com/netflix/conductor/common/metadata/tasks/TaskDef.java index 59e119a0e..7e4357604 100644 --- a/common/src/main/java/com/netflix/conductor/common/metadata/tasks/TaskDef.java +++ b/common/src/main/java/com/netflix/conductor/common/metadata/tasks/TaskDef.java @@ -1,5 +1,5 @@ /* - * Copyright 2021 Netflix, Inc. + * Copyright 2021 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at @@ -18,23 +18,23 @@ import java.util.Map; import java.util.Objects; -import javax.validation.Valid; -import javax.validation.constraints.Email; -import javax.validation.constraints.Min; -import javax.validation.constraints.NotEmpty; -import javax.validation.constraints.NotNull; - import com.netflix.conductor.annotations.protogen.ProtoEnum; import com.netflix.conductor.annotations.protogen.ProtoField; import com.netflix.conductor.annotations.protogen.ProtoMessage; import com.netflix.conductor.common.constraints.OwnerEmailMandatoryConstraint; import com.netflix.conductor.common.constraints.TaskTimeoutConstraint; -import com.netflix.conductor.common.metadata.BaseDef; +import com.netflix.conductor.common.metadata.Auditable; +import com.netflix.conductor.common.metadata.SchemaDef; + +import jakarta.validation.Valid; +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; @ProtoMessage @TaskTimeoutConstraint @Valid -public class TaskDef extends BaseDef { +public class TaskDef extends Auditable { @ProtoEnum public enum TimeoutPolicy { @@ -114,7 +114,6 @@ public enum RetryLogic { @ProtoField(id = 18) @OwnerEmailMandatoryConstraint - @Email(message = "ownerEmail should be valid email address") private String ownerEmail; @ProtoField(id = 19) @@ -125,6 +124,13 @@ public enum RetryLogic { @Min(value = 1, message = "Backoff scale factor. Applicable for LINEAR_BACKOFF") private Integer backoffScaleFactor = 1; + @ProtoField(id = 21) + private String baseType; + + private SchemaDef inputSchema; + private SchemaDef outputSchema; + private boolean enforceSchema; + public TaskDef() {} public TaskDef(String name) { @@ -426,6 +432,38 @@ public Integer getBackoffScaleFactor() { return backoffScaleFactor; } + public String getBaseType() { + return baseType; + } + + public void setBaseType(String baseType) { + this.baseType = baseType; + } + + public SchemaDef getInputSchema() { + return inputSchema; + } + + public void setInputSchema(SchemaDef inputSchema) { + this.inputSchema = inputSchema; + } + + public SchemaDef getOutputSchema() { + return outputSchema; + } + + public void setOutputSchema(SchemaDef outputSchema) { + this.outputSchema = outputSchema; + } + + public boolean isEnforceSchema() { + return enforceSchema; + } + + public void setEnforceSchema(boolean enforceSchema) { + this.enforceSchema = enforceSchema; + } + @Override public String toString() { return name; @@ -456,7 +494,10 @@ && getRetryLogic() == taskDef.getRetryLogic() && Objects.equals(getInputTemplate(), taskDef.getInputTemplate()) && Objects.equals(getIsolationGroupId(), taskDef.getIsolationGroupId()) && Objects.equals(getExecutionNameSpace(), taskDef.getExecutionNameSpace()) - && Objects.equals(getOwnerEmail(), taskDef.getOwnerEmail()); + && Objects.equals(getOwnerEmail(), taskDef.getOwnerEmail()) + && Objects.equals(getBaseType(), taskDef.getBaseType()) + && Objects.equals(getInputSchema(), taskDef.getInputSchema()) + && Objects.equals(getOutputSchema(), taskDef.getOutputSchema()); } @Override @@ -479,6 +520,9 @@ public int hashCode() { getInputTemplate(), getIsolationGroupId(), getExecutionNameSpace(), - getOwnerEmail()); + getOwnerEmail(), + getBaseType(), + getInputSchema(), + getOutputSchema()); } } diff --git a/common/src/main/java/com/netflix/conductor/common/metadata/tasks/TaskExecLog.java b/common/src/main/java/com/netflix/conductor/common/metadata/tasks/TaskExecLog.java index 256e1da6f..a04eb1257 100644 --- a/common/src/main/java/com/netflix/conductor/common/metadata/tasks/TaskExecLog.java +++ b/common/src/main/java/com/netflix/conductor/common/metadata/tasks/TaskExecLog.java @@ -1,5 +1,5 @@ /* - * Copyright 2020 Netflix, Inc. + * Copyright 2020 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/common/src/main/java/com/netflix/conductor/common/metadata/tasks/TaskResult.java b/common/src/main/java/com/netflix/conductor/common/metadata/tasks/TaskResult.java index 8953d499b..704c9fa70 100644 --- a/common/src/main/java/com/netflix/conductor/common/metadata/tasks/TaskResult.java +++ b/common/src/main/java/com/netflix/conductor/common/metadata/tasks/TaskResult.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at @@ -17,8 +17,6 @@ import java.util.Map; import java.util.concurrent.CopyOnWriteArrayList; -import javax.validation.constraints.NotEmpty; - import org.apache.commons.lang3.StringUtils; import com.netflix.conductor.annotations.protogen.ProtoEnum; @@ -27,6 +25,7 @@ import com.google.protobuf.Any; import io.swagger.v3.oas.annotations.Hidden; +import jakarta.validation.constraints.NotEmpty; /** Result of the task execution. */ @ProtoMessage diff --git a/common/src/main/java/com/netflix/conductor/common/metadata/tasks/TaskType.java b/common/src/main/java/com/netflix/conductor/common/metadata/tasks/TaskType.java index 235a0ac91..902027b02 100644 --- a/common/src/main/java/com/netflix/conductor/common/metadata/tasks/TaskType.java +++ b/common/src/main/java/com/netflix/conductor/common/metadata/tasks/TaskType.java @@ -1,5 +1,5 @@ /* - * Copyright 2021 Netflix, Inc. + * Copyright 2021 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/common/src/main/java/com/netflix/conductor/common/metadata/workflow/DynamicForkJoinTask.java b/common/src/main/java/com/netflix/conductor/common/metadata/workflow/DynamicForkJoinTask.java index d95354ef5..05c5dfbfb 100644 --- a/common/src/main/java/com/netflix/conductor/common/metadata/workflow/DynamicForkJoinTask.java +++ b/common/src/main/java/com/netflix/conductor/common/metadata/workflow/DynamicForkJoinTask.java @@ -1,5 +1,5 @@ /* - * Copyright 2021 Netflix, Inc. + * Copyright 2021 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/common/src/main/java/com/netflix/conductor/common/metadata/workflow/DynamicForkJoinTaskList.java b/common/src/main/java/com/netflix/conductor/common/metadata/workflow/DynamicForkJoinTaskList.java index f11530dc7..ca5292b51 100644 --- a/common/src/main/java/com/netflix/conductor/common/metadata/workflow/DynamicForkJoinTaskList.java +++ b/common/src/main/java/com/netflix/conductor/common/metadata/workflow/DynamicForkJoinTaskList.java @@ -1,5 +1,5 @@ /* - * Copyright 2020 Netflix, Inc. + * Copyright 2020 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/common/src/main/java/com/netflix/conductor/common/metadata/workflow/IdempotencyStrategy.java b/common/src/main/java/com/netflix/conductor/common/metadata/workflow/IdempotencyStrategy.java new file mode 100644 index 000000000..4b9ebd60b --- /dev/null +++ b/common/src/main/java/com/netflix/conductor/common/metadata/workflow/IdempotencyStrategy.java @@ -0,0 +1,18 @@ +/* + * Copyright 2020 Conductor Authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package com.netflix.conductor.common.metadata.workflow; + +public enum IdempotencyStrategy { + FAIL, + RETURN_EXISTING +} diff --git a/common/src/main/java/com/netflix/conductor/common/metadata/workflow/RateLimitConfig.java b/common/src/main/java/com/netflix/conductor/common/metadata/workflow/RateLimitConfig.java new file mode 100644 index 000000000..966880f68 --- /dev/null +++ b/common/src/main/java/com/netflix/conductor/common/metadata/workflow/RateLimitConfig.java @@ -0,0 +1,47 @@ +/* + * Copyright 2023 Conductor Authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package com.netflix.conductor.common.metadata.workflow; + +import com.netflix.conductor.annotations.protogen.ProtoField; +import com.netflix.conductor.annotations.protogen.ProtoMessage; + +/** Rate limit configuration for workflows */ +@ProtoMessage +public class RateLimitConfig { + /** + * Key that defines the rate limit. Rate limit key is a combination of workflow payload such as + * name, or correlationId etc. + */ + @ProtoField(id = 1) + private String rateLimitKey; + + /** Number of concurrently running workflows that are allowed per key */ + @ProtoField(id = 2) + private int concurrentExecLimit; + + public String getRateLimitKey() { + return rateLimitKey; + } + + public void setRateLimitKey(String rateLimitKey) { + this.rateLimitKey = rateLimitKey; + } + + public int getConcurrentExecLimit() { + return concurrentExecLimit; + } + + public void setConcurrentExecLimit(int concurrentExecLimit) { + this.concurrentExecLimit = concurrentExecLimit; + } +} diff --git a/common/src/main/java/com/netflix/conductor/common/metadata/workflow/RerunWorkflowRequest.java b/common/src/main/java/com/netflix/conductor/common/metadata/workflow/RerunWorkflowRequest.java index 67c1b86a7..82d802109 100644 --- a/common/src/main/java/com/netflix/conductor/common/metadata/workflow/RerunWorkflowRequest.java +++ b/common/src/main/java/com/netflix/conductor/common/metadata/workflow/RerunWorkflowRequest.java @@ -1,5 +1,5 @@ /* - * Copyright 2020 Netflix, Inc. + * Copyright 2020 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/common/src/main/java/com/netflix/conductor/common/metadata/workflow/SkipTaskRequest.java b/common/src/main/java/com/netflix/conductor/common/metadata/workflow/SkipTaskRequest.java index 8540794a6..42371c943 100644 --- a/common/src/main/java/com/netflix/conductor/common/metadata/workflow/SkipTaskRequest.java +++ b/common/src/main/java/com/netflix/conductor/common/metadata/workflow/SkipTaskRequest.java @@ -1,5 +1,5 @@ /* - * Copyright 2020 Netflix, Inc. + * Copyright 2020 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/common/src/main/java/com/netflix/conductor/common/metadata/workflow/StartWorkflowRequest.java b/common/src/main/java/com/netflix/conductor/common/metadata/workflow/StartWorkflowRequest.java index cc01bca1a..9d76533d6 100644 --- a/common/src/main/java/com/netflix/conductor/common/metadata/workflow/StartWorkflowRequest.java +++ b/common/src/main/java/com/netflix/conductor/common/metadata/workflow/StartWorkflowRequest.java @@ -1,5 +1,5 @@ /* - * Copyright 2020 Netflix, Inc. + * Copyright 2020 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at @@ -15,14 +15,14 @@ import java.util.HashMap; import java.util.Map; -import javax.validation.Valid; -import javax.validation.constraints.Max; -import javax.validation.constraints.Min; -import javax.validation.constraints.NotNull; - import com.netflix.conductor.annotations.protogen.ProtoField; import com.netflix.conductor.annotations.protogen.ProtoMessage; +import jakarta.validation.Valid; +import jakarta.validation.constraints.Max; +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.NotNull; + @ProtoMessage public class StartWorkflowRequest { @@ -54,6 +54,29 @@ public class StartWorkflowRequest { @Max(value = 99, message = "priority: ${validatedValue} should be maximum {value}") private Integer priority = 0; + @ProtoField(id = 9) + private String createdBy; + + private String idempotencyKey; + + private IdempotencyStrategy idempotencyStrategy; + + public String getIdempotencyKey() { + return idempotencyKey; + } + + public void setIdempotencyKey(String idempotencyKey) { + this.idempotencyKey = idempotencyKey; + } + + public IdempotencyStrategy getIdempotencyStrategy() { + return idempotencyStrategy; + } + + public void setIdempotencyStrategy(IdempotencyStrategy idempotencyStrategy) { + this.idempotencyStrategy = idempotencyStrategy; + } + public String getName() { return name; } @@ -158,4 +181,17 @@ public StartWorkflowRequest withWorkflowDef(WorkflowDef workflowDef) { this.workflowDef = workflowDef; return this; } + + public String getCreatedBy() { + return createdBy; + } + + public void setCreatedBy(String createdBy) { + this.createdBy = createdBy; + } + + public StartWorkflowRequest withCreatedBy(String createdBy) { + this.createdBy = createdBy; + return this; + } } diff --git a/common/src/main/java/com/netflix/conductor/common/metadata/workflow/StateChangeEvent.java b/common/src/main/java/com/netflix/conductor/common/metadata/workflow/StateChangeEvent.java new file mode 100644 index 000000000..fc0275a5e --- /dev/null +++ b/common/src/main/java/com/netflix/conductor/common/metadata/workflow/StateChangeEvent.java @@ -0,0 +1,54 @@ +/* + * Copyright 2023 Conductor Authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package com.netflix.conductor.common.metadata.workflow; + +import java.util.Map; + +import com.netflix.conductor.annotations.protogen.ProtoField; +import com.netflix.conductor.annotations.protogen.ProtoMessage; + +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; + +@Valid +@ProtoMessage +public class StateChangeEvent { + + @ProtoField(id = 1) + @NotNull + private String type; + + @ProtoField(id = 2) + private Map payload; + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public Map getPayload() { + return payload; + } + + public void setPayload(Map payload) { + this.payload = payload; + } + + @Override + public String toString() { + return "StateChangeEvent{" + "type='" + type + '\'' + ", payload=" + payload + '}'; + } +} diff --git a/common/src/main/java/com/netflix/conductor/common/metadata/workflow/SubWorkflowParams.java b/common/src/main/java/com/netflix/conductor/common/metadata/workflow/SubWorkflowParams.java index 816981b86..66040b593 100644 --- a/common/src/main/java/com/netflix/conductor/common/metadata/workflow/SubWorkflowParams.java +++ b/common/src/main/java/com/netflix/conductor/common/metadata/workflow/SubWorkflowParams.java @@ -1,5 +1,5 @@ /* - * Copyright 2020 Netflix, Inc. + * Copyright 2020 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at @@ -12,24 +12,22 @@ */ package com.netflix.conductor.common.metadata.workflow; +import java.util.LinkedHashMap; import java.util.Map; import java.util.Objects; -import javax.validation.constraints.NotEmpty; -import javax.validation.constraints.NotNull; - import com.netflix.conductor.annotations.protogen.ProtoField; import com.netflix.conductor.annotations.protogen.ProtoMessage; +import com.netflix.conductor.common.utils.TaskUtils; import com.fasterxml.jackson.annotation.JsonGetter; +import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonSetter; @ProtoMessage public class SubWorkflowParams { @ProtoField(id = 1) - @NotNull(message = "SubWorkflowParams name cannot be null") - @NotEmpty(message = "SubWorkflowParams name cannot be empty") private String name; @ProtoField(id = 2) @@ -43,15 +41,36 @@ public class SubWorkflowParams { @ProtoField(id = 4) private Object workflowDefinition; + private String idempotencyKey; + + private IdempotencyStrategy idempotencyStrategy; + + public String getIdempotencyKey() { + return idempotencyKey; + } + + public void setIdempotencyKey(String idempotencyKey) { + this.idempotencyKey = idempotencyKey; + } + + public IdempotencyStrategy getIdempotencyStrategy() { + return idempotencyStrategy; + } + + public void setIdempotencyStrategy(IdempotencyStrategy idempotencyStrategy) { + this.idempotencyStrategy = idempotencyStrategy; + } + /** * @return the name */ public String getName() { if (workflowDefinition != null) { - return getWorkflowDef().getName(); - } else { - return name; + if (workflowDefinition instanceof WorkflowDef) { + return ((WorkflowDef) workflowDefinition).getName(); + } } + return name; } /** @@ -66,10 +85,11 @@ public void setName(String name) { */ public Integer getVersion() { if (workflowDefinition != null) { - return getWorkflowDef().getVersion(); - } else { - return version; + if (workflowDefinition instanceof WorkflowDef) { + return ((WorkflowDef) workflowDefinition).getVersion(); + } } + return version; } /** @@ -96,14 +116,19 @@ public void setTaskToDomain(Map taskToDomain) { /** * @return the workflowDefinition as an Object */ + @JsonGetter("workflowDefinition") public Object getWorkflowDefinition() { return workflowDefinition; } - /** - * @return the workflowDefinition as a WorkflowDef - */ - @JsonGetter("workflowDefinition") + @Deprecated + @JsonIgnore + public void setWorkflowDef(WorkflowDef workflowDef) { + this.setWorkflowDefinition(workflowDef); + } + + @Deprecated + @JsonIgnore public WorkflowDef getWorkflowDef() { return (WorkflowDef) workflowDefinition; } @@ -111,20 +136,26 @@ public WorkflowDef getWorkflowDef() { /** * @param workflowDef the workflowDefinition to set */ + @JsonSetter("workflowDefinition") public void setWorkflowDefinition(Object workflowDef) { - if (!(workflowDef == null || workflowDef instanceof WorkflowDef)) { + if (workflowDef == null) { + this.workflowDefinition = workflowDef; + } else if (workflowDef instanceof WorkflowDef) { + this.workflowDefinition = workflowDef; + } else if (workflowDef instanceof String) { + if (!(((String) workflowDef).startsWith("${")) + || !(((String) workflowDef).endsWith("}"))) { + throw new IllegalArgumentException( + "workflowDefinition is a string, but not a valid DSL string"); + } else { + this.workflowDefinition = workflowDef; + } + } else if (workflowDef instanceof LinkedHashMap) { + this.workflowDefinition = TaskUtils.convertToWorkflowDef(workflowDef); + } else { throw new IllegalArgumentException( - "workflowDefinition must be either null or WorkflowDef"); + "workflowDefinition must be either null, or WorkflowDef, or a valid DSL string"); } - this.workflowDefinition = workflowDef; - } - - /** - * @param workflowDef the workflowDefinition to set - */ - @JsonSetter("workflowDefinition") - public void setWorkflowDef(WorkflowDef workflowDef) { - this.workflowDefinition = workflowDef; } @Override diff --git a/common/src/main/java/com/netflix/conductor/common/metadata/workflow/UpgradeWorkflowRequest.java b/common/src/main/java/com/netflix/conductor/common/metadata/workflow/UpgradeWorkflowRequest.java new file mode 100644 index 000000000..a33b16874 --- /dev/null +++ b/common/src/main/java/com/netflix/conductor/common/metadata/workflow/UpgradeWorkflowRequest.java @@ -0,0 +1,69 @@ +/* + * Copyright 2023 Conductor Authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package com.netflix.conductor.common.metadata.workflow; + +import java.util.Map; + +import com.netflix.conductor.annotations.protogen.ProtoField; +import com.netflix.conductor.annotations.protogen.ProtoMessage; + +import jakarta.validation.constraints.NotNull; + +@ProtoMessage +public class UpgradeWorkflowRequest { + + public Map getTaskOutput() { + return taskOutput; + } + + public void setTaskOutput(Map taskOutput) { + this.taskOutput = taskOutput; + } + + public Map getWorkflowInput() { + return workflowInput; + } + + public void setWorkflowInput(Map workflowInput) { + this.workflowInput = workflowInput; + } + + @ProtoField(id = 4) + private Map taskOutput; + + @ProtoField(id = 3) + private Map workflowInput; + + @ProtoField(id = 2) + private Integer version; + + @NotNull(message = "Workflow name cannot be null or empty") + @ProtoField(id = 1) + private String name; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Integer getVersion() { + return version; + } + + public void setVersion(Integer version) { + this.version = version; + } +} diff --git a/common/src/main/java/com/netflix/conductor/common/metadata/workflow/WorkflowDef.java b/common/src/main/java/com/netflix/conductor/common/metadata/workflow/WorkflowDef.java index 6ce981f90..2569294b8 100644 --- a/common/src/main/java/com/netflix/conductor/common/metadata/workflow/WorkflowDef.java +++ b/common/src/main/java/com/netflix/conductor/common/metadata/workflow/WorkflowDef.java @@ -1,5 +1,5 @@ /* - * Copyright 2020 Netflix, Inc. + * Copyright 2020 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at @@ -12,19 +12,7 @@ */ package com.netflix.conductor.common.metadata.workflow; -import java.util.HashMap; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Objects; - -import javax.validation.Valid; -import javax.validation.constraints.Email; -import javax.validation.constraints.Max; -import javax.validation.constraints.Min; -import javax.validation.constraints.NotEmpty; -import javax.validation.constraints.NotNull; +import java.util.*; import com.netflix.conductor.annotations.protogen.ProtoEnum; import com.netflix.conductor.annotations.protogen.ProtoField; @@ -32,12 +20,16 @@ import com.netflix.conductor.common.constraints.NoSemiColonConstraint; import com.netflix.conductor.common.constraints.OwnerEmailMandatoryConstraint; import com.netflix.conductor.common.constraints.TaskReferenceNameUniqueConstraint; -import com.netflix.conductor.common.metadata.BaseDef; +import com.netflix.conductor.common.metadata.Auditable; +import com.netflix.conductor.common.metadata.SchemaDef; import com.netflix.conductor.common.metadata.tasks.TaskType; +import jakarta.validation.*; +import jakarta.validation.constraints.*; + @ProtoMessage @TaskReferenceNameUniqueConstraint -public class WorkflowDef extends BaseDef { +public class WorkflowDef extends Auditable { @ProtoEnum public enum TimeoutPolicy { @@ -76,7 +68,7 @@ public enum TimeoutPolicy { @Max(value = 2, message = "workflowDef schemaVersion: {value} is only supported") private int schemaVersion = 2; - // By default, a workflow is restartable + // By default a workflow is restartable @ProtoField(id = 9) private boolean restartable = true; @@ -85,7 +77,6 @@ public enum TimeoutPolicy { @ProtoField(id = 11) @OwnerEmailMandatoryConstraint - @Email(message = "ownerEmail should be valid email address") private String ownerEmail; @ProtoField(id = 12) @@ -101,6 +92,29 @@ public enum TimeoutPolicy { @ProtoField(id = 15) private Map inputTemplate = new HashMap<>(); + @ProtoField(id = 17) + private String workflowStatusListenerSink; + + @ProtoField(id = 18) + private RateLimitConfig rateLimitConfig; + + @ProtoField(id = 19) + private SchemaDef inputSchema; + + @ProtoField(id = 20) + private SchemaDef outputSchema; + + @ProtoField(id = 21) + private boolean enforceSchema = true; + + public boolean isEnforceSchema() { + return enforceSchema; + } + + public void setEnforceSchema(boolean enforceSchema) { + this.enforceSchema = enforceSchema; + } + /** * @return the name */ @@ -321,6 +335,38 @@ public static String getKey(String name, int version) { return name + "." + version; } + public String getWorkflowStatusListenerSink() { + return workflowStatusListenerSink; + } + + public void setWorkflowStatusListenerSink(String workflowStatusListenerSink) { + this.workflowStatusListenerSink = workflowStatusListenerSink; + } + + public RateLimitConfig getRateLimitConfig() { + return rateLimitConfig; + } + + public void setRateLimitConfig(RateLimitConfig rateLimitConfig) { + this.rateLimitConfig = rateLimitConfig; + } + + public SchemaDef getInputSchema() { + return inputSchema; + } + + public void setInputSchema(SchemaDef inputSchema) { + this.inputSchema = inputSchema; + } + + public SchemaDef getOutputSchema() { + return outputSchema; + } + + public void setOutputSchema(SchemaDef outputSchema) { + this.outputSchema = outputSchema; + } + public boolean containsType(String taskType) { return collectTasks().stream().anyMatch(t -> t.getType().equals(taskType)); } @@ -384,31 +430,12 @@ public boolean equals(Object o) { return false; } WorkflowDef that = (WorkflowDef) o; - return getVersion() == that.getVersion() - && getSchemaVersion() == that.getSchemaVersion() - && Objects.equals(getName(), that.getName()) - && Objects.equals(getDescription(), that.getDescription()) - && Objects.equals(getTasks(), that.getTasks()) - && Objects.equals(getInputParameters(), that.getInputParameters()) - && Objects.equals(getOutputParameters(), that.getOutputParameters()) - && Objects.equals(getFailureWorkflow(), that.getFailureWorkflow()) - && Objects.equals(getOwnerEmail(), that.getOwnerEmail()) - && Objects.equals(getTimeoutSeconds(), that.getTimeoutSeconds()); + return version == that.version && Objects.equals(name, that.name); } @Override public int hashCode() { - return Objects.hash( - getName(), - getDescription(), - getVersion(), - getTasks(), - getInputParameters(), - getOutputParameters(), - getFailureWorkflow(), - getSchemaVersion(), - getOwnerEmail(), - getTimeoutSeconds()); + return Objects.hash(name, version); } @Override @@ -437,8 +464,28 @@ public String toString() { + restartable + ", workflowStatusListenerEnabled=" + workflowStatusListenerEnabled + + ", ownerEmail='" + + ownerEmail + + '\'' + + ", timeoutPolicy=" + + timeoutPolicy + ", timeoutSeconds=" + timeoutSeconds + + ", variables=" + + variables + + ", inputTemplate=" + + inputTemplate + + ", workflowStatusListenerSink='" + + workflowStatusListenerSink + + '\'' + + ", rateLimitConfig=" + + rateLimitConfig + + ", inputSchema=" + + inputSchema + + ", outputSchema=" + + outputSchema + + ", enforceSchema=" + + enforceSchema + '}'; } } diff --git a/common/src/main/java/com/netflix/conductor/common/metadata/workflow/WorkflowDefSummary.java b/common/src/main/java/com/netflix/conductor/common/metadata/workflow/WorkflowDefSummary.java index fc0eca86d..6c8d1f36e 100644 --- a/common/src/main/java/com/netflix/conductor/common/metadata/workflow/WorkflowDefSummary.java +++ b/common/src/main/java/com/netflix/conductor/common/metadata/workflow/WorkflowDefSummary.java @@ -1,5 +1,5 @@ /* - * Copyright 2020 Netflix, Inc. + * Copyright 2020 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at @@ -14,12 +14,12 @@ import java.util.Objects; -import javax.validation.constraints.NotEmpty; - import com.netflix.conductor.annotations.protogen.ProtoField; import com.netflix.conductor.annotations.protogen.ProtoMessage; import com.netflix.conductor.common.constraints.NoSemiColonConstraint; +import jakarta.validation.constraints.NotEmpty; + @ProtoMessage public class WorkflowDefSummary implements Comparable { diff --git a/common/src/main/java/com/netflix/conductor/common/metadata/workflow/WorkflowTask.java b/common/src/main/java/com/netflix/conductor/common/metadata/workflow/WorkflowTask.java index 492a61d33..2e42e7319 100644 --- a/common/src/main/java/com/netflix/conductor/common/metadata/workflow/WorkflowTask.java +++ b/common/src/main/java/com/netflix/conductor/common/metadata/workflow/WorkflowTask.java @@ -1,5 +1,5 @@ /* - * Copyright 2021 Netflix, Inc. + * Copyright 2021 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at @@ -21,16 +21,15 @@ import java.util.Map; import java.util.Objects; -import javax.validation.Valid; -import javax.validation.constraints.NotEmpty; -import javax.validation.constraints.PositiveOrZero; - import com.netflix.conductor.annotations.protogen.ProtoField; import com.netflix.conductor.annotations.protogen.ProtoMessage; import com.netflix.conductor.common.metadata.tasks.TaskDef; import com.netflix.conductor.common.metadata.tasks.TaskType; -import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonGetter; +import com.fasterxml.jackson.annotation.JsonSetter; +import jakarta.validation.Valid; +import jakarta.validation.constraints.*; /** * This is the task definition definied as part of the {@link WorkflowDef}. The tasks definied in @@ -39,6 +38,32 @@ @ProtoMessage public class WorkflowTask { + @ProtoMessage + public static class CacheConfig { + + @ProtoField(id = 1) + private String key; + + @ProtoField(id = 2) + private int ttlInSecond; + + public String getKey() { + return key; + } + + public void setKey(String key) { + this.key = key; + } + + public int getTtlInSecond() { + return ttlInSecond; + } + + public void setTtlInSecond(int ttlInSecond) { + this.ttlInSecond = ttlInSecond; + } + } + @ProtoField(id = 1) @NotEmpty(message = "WorkflowTask name cannot be empty or null") private String name; @@ -87,7 +112,6 @@ public void setTasks(List tasks) { // Populates for the tasks of the decision type @ProtoField(id = 9) - @JsonInclude(JsonInclude.Include.NON_EMPTY) private Map> decisionCases = new LinkedHashMap<>(); @Deprecated private String dynamicForkJoinTasksParam; @@ -99,11 +123,9 @@ public void setTasks(List tasks) { private String dynamicForkTasksInputParamName; @ProtoField(id = 12) - @JsonInclude(JsonInclude.Include.NON_EMPTY) private List<@Valid WorkflowTask> defaultCase = new LinkedList<>(); @ProtoField(id = 13) - @JsonInclude(JsonInclude.Include.NON_EMPTY) private List<@Valid List<@Valid WorkflowTask>> forkTasks = new LinkedList<>(); @ProtoField(id = 14) @@ -115,7 +137,6 @@ public void setTasks(List tasks) { private SubWorkflowParams subWorkflowParam; @ProtoField(id = 16) - @JsonInclude(JsonInclude.Include.NON_EMPTY) private List joinOn = new LinkedList<>(); @ProtoField(id = 17) @@ -131,7 +152,6 @@ public void setTasks(List tasks) { private Boolean rateLimited; @ProtoField(id = 21) - @JsonInclude(JsonInclude.Include.NON_EMPTY) private List defaultExclusiveJoinTask = new LinkedList<>(); @ProtoField(id = 23) @@ -141,7 +161,6 @@ public void setTasks(List tasks) { private String loopCondition; @ProtoField(id = 25) - @JsonInclude(JsonInclude.Include.NON_EMPTY) private List loopOver = new LinkedList<>(); @ProtoField(id = 26) @@ -153,6 +172,22 @@ public void setTasks(List tasks) { @ProtoField(id = 28) private String expression; + /* + Map of events to be emitted when the task status changed. + key can be comma separated values of the status changes prefixed with "on" + */ + // @ProtoField(id = 29) + private @Valid Map> onStateChange = new HashMap<>(); + + @ProtoField(id = 30) + private String joinStatus; + + @ProtoField(id = 31) + private CacheConfig cacheConfig; + + @ProtoField(id = 32) + private boolean permissive; + /** * @return the name */ @@ -388,9 +423,18 @@ public void setScriptExpression(String expression) { this.scriptExpression = expression; } + public CacheConfig getCacheConfig() { + return cacheConfig; + } + + public void setCacheConfig(CacheConfig cacheConfig) { + this.cacheConfig = cacheConfig; + } + /** * @return the subWorkflow */ + @JsonGetter public SubWorkflowParams getSubWorkflowParam() { return subWorkflowParam; } @@ -398,6 +442,7 @@ public SubWorkflowParams getSubWorkflowParam() { /** * @param subWorkflow the subWorkflowParam to set */ + @JsonSetter public void setSubWorkflowParam(SubWorkflowParams subWorkflow) { this.subWorkflowParam = subWorkflow; } @@ -548,6 +593,22 @@ public void setExpression(String expression) { this.expression = expression; } + public String getJoinStatus() { + return joinStatus; + } + + public void setJoinStatus(String joinStatus) { + this.joinStatus = joinStatus; + } + + public boolean isPermissive() { + return permissive; + } + + public void setPermissive(boolean permissive) { + this.permissive = permissive; + } + private Collection> children() { Collection> workflowTaskLists = new LinkedList<>(); @@ -695,6 +756,14 @@ public WorkflowTask get(String taskReferenceName) { return null; } + public Map> getOnStateChange() { + return onStateChange; + } + + public void setOnStateChange(Map> onStateChange) { + this.onStateChange = onStateChange; + } + @Override public String toString() { return name + "/" + taskReferenceName; @@ -709,62 +778,12 @@ public boolean equals(Object o) { return false; } WorkflowTask that = (WorkflowTask) o; - return getStartDelay() == that.getStartDelay() - && isOptional() == that.isOptional() - && Objects.equals(getName(), that.getName()) - && Objects.equals(getTaskReferenceName(), that.getTaskReferenceName()) - && Objects.equals(getDescription(), that.getDescription()) - && Objects.equals(getInputParameters(), that.getInputParameters()) - && Objects.equals(getType(), that.getType()) - && Objects.equals(getDynamicTaskNameParam(), that.getDynamicTaskNameParam()) - && Objects.equals(getCaseValueParam(), that.getCaseValueParam()) - && Objects.equals(getEvaluatorType(), that.getEvaluatorType()) - && Objects.equals(getExpression(), that.getExpression()) - && Objects.equals(getCaseExpression(), that.getCaseExpression()) - && Objects.equals(getDecisionCases(), that.getDecisionCases()) - && Objects.equals( - getDynamicForkJoinTasksParam(), that.getDynamicForkJoinTasksParam()) - && Objects.equals(getDynamicForkTasksParam(), that.getDynamicForkTasksParam()) - && Objects.equals( - getDynamicForkTasksInputParamName(), - that.getDynamicForkTasksInputParamName()) - && Objects.equals(getDefaultCase(), that.getDefaultCase()) - && Objects.equals(getForkTasks(), that.getForkTasks()) - && Objects.equals(getSubWorkflowParam(), that.getSubWorkflowParam()) - && Objects.equals(getJoinOn(), that.getJoinOn()) - && Objects.equals(getSink(), that.getSink()) - && Objects.equals(isAsyncComplete(), that.isAsyncComplete()) - && Objects.equals(getDefaultExclusiveJoinTask(), that.getDefaultExclusiveJoinTask()) - && Objects.equals(getRetryCount(), that.getRetryCount()); + return Objects.equals(name, that.name) + && Objects.equals(taskReferenceName, that.taskReferenceName); } @Override public int hashCode() { - - return Objects.hash( - getName(), - getTaskReferenceName(), - getDescription(), - getInputParameters(), - getType(), - getDynamicTaskNameParam(), - getCaseValueParam(), - getCaseExpression(), - getEvaluatorType(), - getExpression(), - getDecisionCases(), - getDynamicForkJoinTasksParam(), - getDynamicForkTasksParam(), - getDynamicForkTasksInputParamName(), - getDefaultCase(), - getForkTasks(), - getStartDelay(), - getSubWorkflowParam(), - getJoinOn(), - getSink(), - isAsyncComplete(), - isOptional(), - getDefaultExclusiveJoinTask(), - getRetryCount()); + return Objects.hash(name, taskReferenceName); } } diff --git a/common/src/main/java/com/netflix/conductor/common/model/BulkResponse.java b/common/src/main/java/com/netflix/conductor/common/model/BulkResponse.java index b0f5b38e6..b4133b5bf 100644 --- a/common/src/main/java/com/netflix/conductor/common/model/BulkResponse.java +++ b/common/src/main/java/com/netflix/conductor/common/model/BulkResponse.java @@ -1,5 +1,5 @@ /* - * Copyright 2020 Netflix, Inc. + * Copyright 2020 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/common/src/main/java/com/netflix/conductor/common/run/ExternalStorageLocation.java b/common/src/main/java/com/netflix/conductor/common/run/ExternalStorageLocation.java index 5c3071613..d94b35837 100644 --- a/common/src/main/java/com/netflix/conductor/common/run/ExternalStorageLocation.java +++ b/common/src/main/java/com/netflix/conductor/common/run/ExternalStorageLocation.java @@ -1,5 +1,5 @@ /* - * Copyright 2020 Netflix, Inc. + * Copyright 2020 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/common/src/main/java/com/netflix/conductor/common/run/SearchResult.java b/common/src/main/java/com/netflix/conductor/common/run/SearchResult.java index 72be415a9..43057d985 100644 --- a/common/src/main/java/com/netflix/conductor/common/run/SearchResult.java +++ b/common/src/main/java/com/netflix/conductor/common/run/SearchResult.java @@ -1,5 +1,5 @@ /* - * Copyright 2020 Netflix, Inc. + * Copyright 2020 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/common/src/main/java/com/netflix/conductor/common/run/TaskSummary.java b/common/src/main/java/com/netflix/conductor/common/run/TaskSummary.java index b9e0baa6c..32e3b0f71 100644 --- a/common/src/main/java/com/netflix/conductor/common/run/TaskSummary.java +++ b/common/src/main/java/com/netflix/conductor/common/run/TaskSummary.java @@ -1,5 +1,5 @@ /* - * Copyright 2020 Netflix, Inc. + * Copyright 2020 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/common/src/main/java/com/netflix/conductor/common/run/Workflow.java b/common/src/main/java/com/netflix/conductor/common/run/Workflow.java index 6936f9535..866d01a5e 100644 --- a/common/src/main/java/com/netflix/conductor/common/run/Workflow.java +++ b/common/src/main/java/com/netflix/conductor/common/run/Workflow.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at @@ -15,9 +15,6 @@ import java.util.*; import java.util.stream.Collectors; -import javax.validation.constraints.Max; -import javax.validation.constraints.Min; - import org.apache.commons.lang3.StringUtils; import com.netflix.conductor.annotations.protogen.ProtoEnum; @@ -27,6 +24,9 @@ import com.netflix.conductor.common.metadata.tasks.Task; import com.netflix.conductor.common.metadata.workflow.WorkflowDef; +import jakarta.validation.constraints.Max; +import jakarta.validation.constraints.Min; + @ProtoMessage public class Workflow extends Auditable { @@ -126,8 +126,47 @@ public boolean isSuccessful() { @ProtoField(id = 25) private Set failedTaskNames = new HashSet<>(); + @ProtoField(id = 26) + private List history = new LinkedList<>(); + + private String idempotencyKey; + private String rateLimitKey; + private boolean rateLimited; + public Workflow() {} + public String getIdempotencyKey() { + return idempotencyKey; + } + + public void setIdempotencyKey(String idempotencyKey) { + this.idempotencyKey = idempotencyKey; + } + + public String getRateLimitKey() { + return rateLimitKey; + } + + public void setRateLimitKey(String rateLimitKey) { + this.rateLimitKey = rateLimitKey; + } + + public boolean isRateLimited() { + return rateLimited; + } + + public void setRateLimited(boolean rateLimited) { + this.rateLimited = rateLimited; + } + + public List getHistory() { + return history; + } + + public void setHistory(List history) { + this.history = history; + } + /** * @return the status */ @@ -326,14 +365,6 @@ public void setFailedReferenceTaskNames(Set failedReferenceTaskNames) { this.failedReferenceTaskNames = failedReferenceTaskNames; } - public Set getFailedTaskNames() { - return failedTaskNames; - } - - public void setFailedTaskNames(Set failedTaskNames) { - this.failedTaskNames = failedTaskNames; - } - public WorkflowDef getWorkflowDefinition() { return workflowDefinition; } @@ -447,6 +478,14 @@ public boolean hasParent() { return StringUtils.isNotEmpty(parentWorkflowId); } + public Set getFailedTaskNames() { + return failedTaskNames; + } + + public void setFailedTaskNames(Set failedTaskNames) { + this.failedTaskNames = failedTaskNames; + } + public Task getTaskByRefName(String refName) { if (refName == null) { throw new RuntimeException( @@ -495,7 +534,6 @@ public Workflow copy() { copy.setLastRetriedTime(lastRetriedTime); copy.setTaskToDomain(taskToDomain); copy.setFailedReferenceTaskNames(failedReferenceTaskNames); - copy.setFailedTaskNames(failedTaskNames); copy.setExternalInputPayloadStoragePath(externalInputPayloadStoragePath); copy.setExternalOutputPayloadStoragePath(externalOutputPayloadStoragePath); return copy; @@ -527,61 +565,11 @@ public boolean equals(Object o) { return false; } Workflow workflow = (Workflow) o; - return getEndTime() == workflow.getEndTime() - && getWorkflowVersion() == workflow.getWorkflowVersion() - && getStatus() == workflow.getStatus() - && Objects.equals(getWorkflowId(), workflow.getWorkflowId()) - && Objects.equals(getParentWorkflowId(), workflow.getParentWorkflowId()) - && Objects.equals(getParentWorkflowTaskId(), workflow.getParentWorkflowTaskId()) - && Objects.equals(getTasks(), workflow.getTasks()) - && Objects.equals(getInput(), workflow.getInput()) - && Objects.equals(getOutput(), workflow.getOutput()) - && Objects.equals(getWorkflowName(), workflow.getWorkflowName()) - && Objects.equals(getCorrelationId(), workflow.getCorrelationId()) - && Objects.equals(getReRunFromWorkflowId(), workflow.getReRunFromWorkflowId()) - && Objects.equals(getReasonForIncompletion(), workflow.getReasonForIncompletion()) - && Objects.equals(getEvent(), workflow.getEvent()) - && Objects.equals(getTaskToDomain(), workflow.getTaskToDomain()) - && Objects.equals( - getFailedReferenceTaskNames(), workflow.getFailedReferenceTaskNames()) - && Objects.equals(getFailedTaskNames(), workflow.getFailedTaskNames()) - && Objects.equals( - getExternalInputPayloadStoragePath(), - workflow.getExternalInputPayloadStoragePath()) - && Objects.equals( - getExternalOutputPayloadStoragePath(), - workflow.getExternalOutputPayloadStoragePath()) - && Objects.equals(getPriority(), workflow.getPriority()) - && Objects.equals(getWorkflowDefinition(), workflow.getWorkflowDefinition()) - && Objects.equals(getVariables(), workflow.getVariables()) - && Objects.equals(getLastRetriedTime(), workflow.getLastRetriedTime()); + return Objects.equals(getWorkflowId(), workflow.getWorkflowId()); } @Override public int hashCode() { - return Objects.hash( - getStatus(), - getEndTime(), - getWorkflowId(), - getParentWorkflowId(), - getParentWorkflowTaskId(), - getTasks(), - getInput(), - getOutput(), - getWorkflowName(), - getWorkflowVersion(), - getCorrelationId(), - getReRunFromWorkflowId(), - getReasonForIncompletion(), - getEvent(), - getTaskToDomain(), - getFailedReferenceTaskNames(), - getFailedTaskNames(), - getWorkflowDefinition(), - getExternalInputPayloadStoragePath(), - getExternalOutputPayloadStoragePath(), - getPriority(), - getVariables(), - getLastRetriedTime()); + return Objects.hash(getWorkflowId()); } } diff --git a/common/src/main/java/com/netflix/conductor/common/run/WorkflowSummary.java b/common/src/main/java/com/netflix/conductor/common/run/WorkflowSummary.java index 7fec015fc..c41a8f69c 100644 --- a/common/src/main/java/com/netflix/conductor/common/run/WorkflowSummary.java +++ b/common/src/main/java/com/netflix/conductor/common/run/WorkflowSummary.java @@ -1,5 +1,5 @@ /* - * Copyright 2020 Netflix, Inc. + * Copyright 2020 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at @@ -88,6 +88,9 @@ public class WorkflowSummary { @ProtoField(id = 18) private Set failedTaskNames = new HashSet<>(); + @ProtoField(id = 19) + private String createdBy; + public WorkflowSummary() {} public WorkflowSummary(Workflow workflow) { @@ -346,6 +349,14 @@ public void setPriority(int priority) { this.priority = priority; } + public String getCreatedBy() { + return createdBy; + } + + public void setCreatedBy(String createdBy) { + this.createdBy = createdBy; + } + @Override public boolean equals(Object o) { if (this == o) { @@ -366,7 +377,8 @@ && getWorkflowId().equals(that.getWorkflowId()) && StringUtils.equals(getEndTime(), that.getEndTime()) && getStatus() == that.getStatus() && Objects.equals(getReasonForIncompletion(), that.getReasonForIncompletion()) - && Objects.equals(getEvent(), that.getEvent()); + && Objects.equals(getEvent(), that.getEvent()) + && Objects.equals(getCreatedBy(), that.getCreatedBy()); } @Override @@ -383,6 +395,7 @@ public int hashCode() { getReasonForIncompletion(), getExecutionTime(), getEvent(), - getPriority()); + getPriority(), + getCreatedBy()); } } diff --git a/common/src/main/java/com/netflix/conductor/common/run/WorkflowTestRequest.java b/common/src/main/java/com/netflix/conductor/common/run/WorkflowTestRequest.java index e5007348b..e41394688 100644 --- a/common/src/main/java/com/netflix/conductor/common/run/WorkflowTestRequest.java +++ b/common/src/main/java/com/netflix/conductor/common/run/WorkflowTestRequest.java @@ -1,5 +1,5 @@ /* - * Copyright 2023 Netflix, Inc. + * Copyright 2023 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/common/src/main/java/com/netflix/conductor/common/utils/ConstraintParamUtil.java b/common/src/main/java/com/netflix/conductor/common/utils/ConstraintParamUtil.java index 3f2eea503..249db9dcd 100644 --- a/common/src/main/java/com/netflix/conductor/common/utils/ConstraintParamUtil.java +++ b/common/src/main/java/com/netflix/conductor/common/utils/ConstraintParamUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2020 Netflix, Inc. + * Copyright 2020 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/common/src/main/java/com/netflix/conductor/common/utils/EnvUtils.java b/common/src/main/java/com/netflix/conductor/common/utils/EnvUtils.java index 202f1f31c..7cb8ab463 100644 --- a/common/src/main/java/com/netflix/conductor/common/utils/EnvUtils.java +++ b/common/src/main/java/com/netflix/conductor/common/utils/EnvUtils.java @@ -1,5 +1,5 @@ /* - * Copyright 2020 Netflix, Inc. + * Copyright 2020 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/common/src/main/java/com/netflix/conductor/common/utils/ExternalPayloadStorage.java b/common/src/main/java/com/netflix/conductor/common/utils/ExternalPayloadStorage.java index abe74c734..f246b84b7 100644 --- a/common/src/main/java/com/netflix/conductor/common/utils/ExternalPayloadStorage.java +++ b/common/src/main/java/com/netflix/conductor/common/utils/ExternalPayloadStorage.java @@ -1,5 +1,5 @@ /* - * Copyright 2020 Netflix, Inc. + * Copyright 2020 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/common/src/main/java/com/netflix/conductor/common/utils/SummaryUtil.java b/common/src/main/java/com/netflix/conductor/common/utils/SummaryUtil.java index 76127124e..85c0e2010 100644 --- a/common/src/main/java/com/netflix/conductor/common/utils/SummaryUtil.java +++ b/common/src/main/java/com/netflix/conductor/common/utils/SummaryUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2021 Netflix, Inc. + * Copyright 2021 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at @@ -14,8 +14,6 @@ import java.util.Map; -import javax.annotation.PostConstruct; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; @@ -25,6 +23,7 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; +import jakarta.annotation.PostConstruct; @Component public class SummaryUtil { diff --git a/common/src/main/java/com/netflix/conductor/common/utils/TaskUtils.java b/common/src/main/java/com/netflix/conductor/common/utils/TaskUtils.java index 5e83bd73e..7bb6ab7ff 100644 --- a/common/src/main/java/com/netflix/conductor/common/utils/TaskUtils.java +++ b/common/src/main/java/com/netflix/conductor/common/utils/TaskUtils.java @@ -1,5 +1,5 @@ /* - * Copyright 2020 Netflix, Inc. + * Copyright 2020 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at @@ -12,8 +12,21 @@ */ package com.netflix.conductor.common.utils; +import com.netflix.conductor.common.config.ObjectMapperProvider; +import com.netflix.conductor.common.metadata.workflow.WorkflowDef; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; + public class TaskUtils { + private static final ObjectMapper objectMapper; + + static { + ObjectMapperProvider provider = new ObjectMapperProvider(); + objectMapper = provider.getObjectMapper(); + } + private static final String LOOP_TASK_DELIMITER = "__"; public static String appendIteration(String name, int iteration) { @@ -28,4 +41,8 @@ public static String removeIterationFromTaskRefName(String referenceTaskName) { String[] tokens = referenceTaskName.split(TaskUtils.LOOP_TASK_DELIMITER); return tokens.length > 0 ? tokens[0] : referenceTaskName; } + + public static WorkflowDef convertToWorkflowDef(Object workflowDef) { + return objectMapper.convertValue(workflowDef, new TypeReference() {}); + } } diff --git a/common/src/main/java/com/netflix/conductor/common/validation/ErrorResponse.java b/common/src/main/java/com/netflix/conductor/common/validation/ErrorResponse.java index 5ed6256e1..a43a91197 100644 --- a/common/src/main/java/com/netflix/conductor/common/validation/ErrorResponse.java +++ b/common/src/main/java/com/netflix/conductor/common/validation/ErrorResponse.java @@ -1,5 +1,5 @@ /* - * Copyright 2020 Netflix, Inc. + * Copyright 2020 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at @@ -13,6 +13,7 @@ package com.netflix.conductor.common.validation; import java.util.List; +import java.util.Map; public class ErrorResponse { @@ -23,6 +24,16 @@ public class ErrorResponse { private boolean retryable; private List validationErrors; + private Map metadata; + + public Map getMetadata() { + return metadata; + } + + public void setMetadata(Map metadata) { + this.metadata = metadata; + } + public int getStatus() { return status; } diff --git a/common/src/main/java/com/netflix/conductor/common/validation/ValidationError.java b/common/src/main/java/com/netflix/conductor/common/validation/ValidationError.java index 48a53e066..82d63f520 100644 --- a/common/src/main/java/com/netflix/conductor/common/validation/ValidationError.java +++ b/common/src/main/java/com/netflix/conductor/common/validation/ValidationError.java @@ -1,5 +1,5 @@ /* - * Copyright 2020 Netflix, Inc. + * Copyright 2020 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/common/src/test/java/com/netflix/conductor/common/config/TestObjectMapperConfiguration.java b/common/src/test/java/com/netflix/conductor/common/config/TestObjectMapperConfiguration.java index 014a118dd..b835693f9 100644 --- a/common/src/test/java/com/netflix/conductor/common/config/TestObjectMapperConfiguration.java +++ b/common/src/test/java/com/netflix/conductor/common/config/TestObjectMapperConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2021 Netflix, Inc. + * Copyright 2021 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/common/src/test/java/com/netflix/conductor/common/events/EventHandlerTest.java b/common/src/test/java/com/netflix/conductor/common/events/EventHandlerTest.java index a6a1f5cd1..db23c69dd 100644 --- a/common/src/test/java/com/netflix/conductor/common/events/EventHandlerTest.java +++ b/common/src/test/java/com/netflix/conductor/common/events/EventHandlerTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2020 Netflix, Inc. + * Copyright 2020 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at @@ -16,15 +16,15 @@ import java.util.List; import java.util.Set; -import javax.validation.ConstraintViolation; -import javax.validation.Validation; -import javax.validation.Validator; -import javax.validation.ValidatorFactory; - import org.junit.Test; import com.netflix.conductor.common.metadata.events.EventHandler; +import jakarta.validation.ConstraintViolation; +import jakarta.validation.Validation; +import jakarta.validation.Validator; +import jakarta.validation.ValidatorFactory; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; diff --git a/common/src/test/java/com/netflix/conductor/common/run/TaskSummaryTest.java b/common/src/test/java/com/netflix/conductor/common/run/TaskSummaryTest.java index 4c8ec4e6c..09c7077c1 100644 --- a/common/src/test/java/com/netflix/conductor/common/run/TaskSummaryTest.java +++ b/common/src/test/java/com/netflix/conductor/common/run/TaskSummaryTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2021 Netflix, Inc. + * Copyright 2021 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/common/src/test/java/com/netflix/conductor/common/tasks/TaskDefTest.java b/common/src/test/java/com/netflix/conductor/common/tasks/TaskDefTest.java index 41f966779..a46cf7d5c 100644 --- a/common/src/test/java/com/netflix/conductor/common/tasks/TaskDefTest.java +++ b/common/src/test/java/com/netflix/conductor/common/tasks/TaskDefTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2020 Netflix, Inc. + * Copyright 2020 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at @@ -16,16 +16,16 @@ import java.util.List; import java.util.Set; -import javax.validation.ConstraintViolation; -import javax.validation.Validation; -import javax.validation.Validator; -import javax.validation.ValidatorFactory; - import org.junit.Before; import org.junit.Test; import com.netflix.conductor.common.metadata.tasks.TaskDef; +import jakarta.validation.ConstraintViolation; +import jakarta.validation.Validation; +import jakarta.validation.Validator; +import jakarta.validation.ValidatorFactory; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; @@ -74,24 +74,6 @@ public void testTaskDef() { assertTrue(validationErrors.contains("ownerEmail cannot be empty")); } - @Test - public void testTaskDefNameAndOwnerNotSet() { - TaskDef taskDef = new TaskDef(); - taskDef.setRetryCount(-1); - taskDef.setTimeoutSeconds(1000); - taskDef.setResponseTimeoutSeconds(1); - - Set> result = validator.validate(taskDef); - assertEquals(3, result.size()); - - List validationErrors = new ArrayList<>(); - result.forEach(e -> validationErrors.add(e.getMessage())); - - assertTrue(validationErrors.contains("TaskDef retryCount: 0 must be >= 0")); - assertTrue(validationErrors.contains("TaskDef name cannot be null or empty")); - assertTrue(validationErrors.contains("ownerEmail cannot be empty")); - } - @Test public void testTaskDefInvalidEmail() { TaskDef taskDef = new TaskDef(); @@ -99,7 +81,6 @@ public void testTaskDefInvalidEmail() { taskDef.setRetryCount(1); taskDef.setTimeoutSeconds(1000); taskDef.setResponseTimeoutSeconds(1); - taskDef.setOwnerEmail("owner"); Set> result = validator.validate(taskDef); assertEquals(1, result.size()); @@ -107,7 +88,9 @@ public void testTaskDefInvalidEmail() { List validationErrors = new ArrayList<>(); result.forEach(e -> validationErrors.add(e.getMessage())); - assertTrue(validationErrors.contains("ownerEmail should be valid email address")); + assertTrue( + validationErrors.toString(), + validationErrors.contains("ownerEmail cannot be empty")); } @Test diff --git a/common/src/test/java/com/netflix/conductor/common/tasks/TaskResultTest.java b/common/src/test/java/com/netflix/conductor/common/tasks/TaskResultTest.java index a49fa2daf..54888202d 100644 --- a/common/src/test/java/com/netflix/conductor/common/tasks/TaskResultTest.java +++ b/common/src/test/java/com/netflix/conductor/common/tasks/TaskResultTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2020 Netflix, Inc. + * Copyright 2020 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/common/src/test/java/com/netflix/conductor/common/tasks/TaskTest.java b/common/src/test/java/com/netflix/conductor/common/tasks/TaskTest.java index e392f65b5..402fcfcb0 100644 --- a/common/src/test/java/com/netflix/conductor/common/tasks/TaskTest.java +++ b/common/src/test/java/com/netflix/conductor/common/tasks/TaskTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2020 Netflix, Inc. + * Copyright 2020 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at @@ -98,7 +98,7 @@ public void testDeepCopyTask() { final Task task = new Task(); // In order to avoid forgetting putting inside the copy method the newly added fields check // the number of declared fields. - final int expectedTaskFieldsNumber = 40; + final int expectedTaskFieldsNumber = 41; final int declaredFieldsNumber = task.getClass().getDeclaredFields().length; assertEquals(expectedTaskFieldsNumber, declaredFieldsNumber); diff --git a/common/src/test/java/com/netflix/conductor/common/utils/ConstraintParamUtilTest.java b/common/src/test/java/com/netflix/conductor/common/utils/ConstraintParamUtilTest.java index d29f1744e..543035054 100644 --- a/common/src/test/java/com/netflix/conductor/common/utils/ConstraintParamUtilTest.java +++ b/common/src/test/java/com/netflix/conductor/common/utils/ConstraintParamUtilTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2020 Netflix, Inc. + * Copyright 2020 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/common/src/test/java/com/netflix/conductor/common/utils/SummaryUtilTest.java b/common/src/test/java/com/netflix/conductor/common/utils/SummaryUtilTest.java index 79fae89d9..435434f28 100644 --- a/common/src/test/java/com/netflix/conductor/common/utils/SummaryUtilTest.java +++ b/common/src/test/java/com/netflix/conductor/common/utils/SummaryUtilTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2021 Netflix, Inc. + * Copyright 2021 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/common/src/test/java/com/netflix/conductor/common/workflow/SubWorkflowParamsTest.java b/common/src/test/java/com/netflix/conductor/common/workflow/SubWorkflowParamsTest.java index 1859c4a0d..5d9222d62 100644 --- a/common/src/test/java/com/netflix/conductor/common/workflow/SubWorkflowParamsTest.java +++ b/common/src/test/java/com/netflix/conductor/common/workflow/SubWorkflowParamsTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2021 Netflix, Inc. + * Copyright 2021 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at @@ -12,16 +12,9 @@ */ package com.netflix.conductor.common.workflow; -import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; -import java.util.List; import java.util.Map; -import java.util.Set; - -import javax.validation.ConstraintViolation; -import javax.validation.Validation; -import javax.validation.Validator; -import javax.validation.ValidatorFactory; import org.junit.Test; import org.junit.runner.RunWith; @@ -30,6 +23,8 @@ import org.springframework.test.context.junit4.SpringRunner; import com.netflix.conductor.common.config.TestObjectMapperConfiguration; +import com.netflix.conductor.common.metadata.tasks.TaskDef; +import com.netflix.conductor.common.metadata.tasks.TaskType; import com.netflix.conductor.common.metadata.workflow.SubWorkflowParams; import com.netflix.conductor.common.metadata.workflow.WorkflowDef; import com.netflix.conductor.common.metadata.workflow.WorkflowTask; @@ -39,7 +34,6 @@ import com.fasterxml.jackson.databind.SerializationFeature; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; @ContextConfiguration(classes = {TestObjectMapperConfiguration.class}) @RunWith(SpringRunner.class) @@ -47,22 +41,6 @@ public class SubWorkflowParamsTest { @Autowired private ObjectMapper objectMapper; - @Test - public void testWorkflowTaskName() { - SubWorkflowParams subWorkflowParams = new SubWorkflowParams(); // name is null - ValidatorFactory factory = Validation.buildDefaultValidatorFactory(); - Validator validator = factory.getValidator(); - - Set> result = validator.validate(subWorkflowParams); - assertEquals(2, result.size()); - - List validationErrors = new ArrayList<>(); - result.forEach(e -> validationErrors.add(e.getMessage())); - - assertTrue(validationErrors.contains("SubWorkflowParams name cannot be null")); - assertTrue(validationErrors.contains("SubWorkflowParams name cannot be empty")); - } - @Test public void testWorkflowSetTaskToDomain() { SubWorkflowParams subWorkflowParams = new SubWorkflowParams(); @@ -92,7 +70,6 @@ public void testGetWorkflowDef() { def.getTasks().add(task); subWorkflowParams.setWorkflowDefinition(def); assertEquals(def, subWorkflowParams.getWorkflowDefinition()); - assertEquals(def, subWorkflowParams.getWorkflowDef()); } @Test @@ -116,7 +93,41 @@ public void testWorkflowDefJson() throws Exception { objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(subWorkflowParams); SubWorkflowParams deserializedParams = objectMapper.readValue(serializedParams, SubWorkflowParams.class); - assertEquals(def, deserializedParams.getWorkflowDefinition()); - assertEquals(def, deserializedParams.getWorkflowDef()); + var x = (WorkflowDef) deserializedParams.getWorkflowDefinition(); + assertEquals(def, x); + + var taskName = "taskName"; + var subWorkflowName = "subwf"; + TaskDef taskDef = new TaskDef(taskName); + taskDef.setRetryCount(0); + taskDef.setOwnerEmail("test@orkes.io"); + + WorkflowTask inline = new WorkflowTask(); + inline.setTaskReferenceName(taskName); + inline.setName(taskName); + inline.setTaskDefinition(taskDef); + inline.setWorkflowTaskType(TaskType.SIMPLE); + inline.setInputParameters(Map.of("evaluatorType", "graaljs", "expression", "true;")); + + WorkflowDef subworkflowDef = new WorkflowDef(); + subworkflowDef.setName(subWorkflowName); + subworkflowDef.setOwnerEmail("test@orkes.io"); + subworkflowDef.setInputParameters(Arrays.asList("value", "inlineValue")); + subworkflowDef.setDescription("Sub Workflow to test retry"); + subworkflowDef.setTimeoutSeconds(600); + subworkflowDef.setTimeoutPolicy(WorkflowDef.TimeoutPolicy.TIME_OUT_WF); + subworkflowDef.setTasks(Arrays.asList(inline)); + + // autowired + var serializedSubWorkflowDef1 = objectMapper.writeValueAsString(subworkflowDef); + var deserializedSubWorkflowDef1 = + objectMapper.readValue(serializedSubWorkflowDef1, WorkflowDef.class); + assertEquals(deserializedSubWorkflowDef1, subworkflowDef); + // default + ObjectMapper mapper = new ObjectMapper(); + var serializedSubWorkflowDef2 = mapper.writeValueAsString(subworkflowDef); + var deserializedSubWorkflowDef2 = + mapper.readValue(serializedSubWorkflowDef2, WorkflowDef.class); + assertEquals(deserializedSubWorkflowDef2, subworkflowDef); } } diff --git a/common/src/test/java/com/netflix/conductor/common/workflow/WorkflowDefValidatorTest.java b/common/src/test/java/com/netflix/conductor/common/workflow/WorkflowDefValidatorTest.java index 16a08851e..132e33d99 100644 --- a/common/src/test/java/com/netflix/conductor/common/workflow/WorkflowDefValidatorTest.java +++ b/common/src/test/java/com/netflix/conductor/common/workflow/WorkflowDefValidatorTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2020 Netflix, Inc. + * Copyright 2020 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at @@ -18,11 +18,6 @@ import java.util.Map; import java.util.Set; -import javax.validation.ConstraintViolation; -import javax.validation.Validation; -import javax.validation.Validator; -import javax.validation.ValidatorFactory; - import org.junit.Before; import org.junit.Test; @@ -30,6 +25,11 @@ import com.netflix.conductor.common.metadata.workflow.WorkflowDef; import com.netflix.conductor.common.metadata.workflow.WorkflowTask; +import jakarta.validation.ConstraintViolation; +import jakarta.validation.Validation; +import jakarta.validation.Validator; +import jakarta.validation.ValidatorFactory; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; @@ -327,12 +327,7 @@ public void testWorkflowOwnerInvalidEmail() { ValidatorFactory factory = Validation.buildDefaultValidatorFactory(); Validator validator = factory.getValidator(); Set> result = validator.validate(workflowDef); - assertEquals(1, result.size()); - - List validationErrors = new ArrayList<>(); - result.forEach(e -> validationErrors.add(e.getMessage())); - - assertTrue(validationErrors.contains("ownerEmail should be valid email address")); + assertEquals(0, result.size()); } @Test diff --git a/common/src/test/java/com/netflix/conductor/common/workflow/WorkflowTaskTest.java b/common/src/test/java/com/netflix/conductor/common/workflow/WorkflowTaskTest.java index 6d052e4d3..12a8aa399 100644 --- a/common/src/test/java/com/netflix/conductor/common/workflow/WorkflowTaskTest.java +++ b/common/src/test/java/com/netflix/conductor/common/workflow/WorkflowTaskTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2020 Netflix, Inc. + * Copyright 2020 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at @@ -16,16 +16,16 @@ import java.util.List; import java.util.Set; -import javax.validation.ConstraintViolation; -import javax.validation.Validation; -import javax.validation.Validator; -import javax.validation.ValidatorFactory; - import org.junit.Test; import com.netflix.conductor.common.metadata.tasks.TaskType; import com.netflix.conductor.common.metadata.workflow.WorkflowTask; +import jakarta.validation.ConstraintViolation; +import jakarta.validation.Validation; +import jakarta.validation.Validator; +import jakarta.validation.ValidatorFactory; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; diff --git a/core/build.gradle b/core/build.gradle index d1780f10e..beef8f7a2 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -1,5 +1,5 @@ /* - * Copyright 2021 Netflix, Inc. + * Copyright 2023 Conductor authors *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at @@ -55,7 +55,7 @@ dependencies { testImplementation 'org.springframework.retry:spring-retry' testImplementation project(':conductor-common').sourceSets.test.output - testImplementation "org.codehaus.groovy:groovy-all:${revGroovy}" + testImplementation "org.apache.groovy:groovy-all:${revGroovy}" testImplementation "org.spockframework:spock-core:${revSpock}" testImplementation "org.spockframework:spock-spring:${revSpock}" testImplementation "org.junit.vintage:junit-vintage-engine" diff --git a/core/dependencies.lock b/core/dependencies.lock deleted file mode 100644 index 1355a2115..000000000 --- a/core/dependencies.lock +++ /dev/null @@ -1,616 +0,0 @@ -{ - "annotationProcessor": { - "org.springframework.boot:spring-boot-configuration-processor": { - "locked": "2.7.16" - } - }, - "compileClasspath": { - "com.fasterxml.jackson.core:jackson-annotations": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.core:jackson-core": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.core:jackson-databind": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.dataformat:jackson-dataformat-cbor": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.dataformat:jackson-dataformat-smile": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.dataformat:jackson-dataformat-yaml": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.datatype:jackson-datatype-jdk8": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.datatype:jackson-datatype-joda": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.datatype:jackson-datatype-jsr310": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.module:jackson-module-afterburner": { - "locked": "2.15.0" - }, - "com.github.ben-manes.caffeine:caffeine": { - "locked": "2.9.3" - }, - "com.google.protobuf:protobuf-java": { - "locked": "3.24.3" - }, - "com.jayway.jsonpath:json-path": { - "locked": "2.4.0" - }, - "com.netflix.conductor:conductor-common": { - "project": true - }, - "com.netflix.spectator:spectator-api": { - "locked": "0.122.0" - }, - "com.spotify:completable-futures": { - "locked": "0.3.3" - }, - "commons-io:commons-io": { - "locked": "2.7" - }, - "io.reactivex:rxjava": { - "locked": "1.2.2" - }, - "jakarta.activation:jakarta.activation-api": { - "locked": "2.0.0" - }, - "jakarta.xml.bind:jakarta.xml.bind-api": { - "locked": "2.3.3" - }, - "org.apache.bval:bval-jsr": { - "locked": "2.0.6" - }, - "org.apache.commons:commons-lang3": { - "locked": "3.12.0" - }, - "org.apache.logging.log4j:log4j-api": { - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-core": { - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-jul": { - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-slf4j-impl": { - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-web": { - "locked": "2.17.2" - }, - "org.openjdk.nashorn:nashorn-core": { - "locked": "15.4" - }, - "org.springframework.boot:spring-boot-starter": { - "locked": "2.7.16" - }, - "org.springframework.boot:spring-boot-starter-validation": { - "locked": "2.7.16" - }, - "org.springframework.retry:spring-retry": { - "locked": "1.3.4" - }, - "org.yaml:snakeyaml": { - "locked": "2.0" - } - }, - "runtimeClasspath": { - "com.fasterxml.jackson.core:jackson-annotations": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.core:jackson-core": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.core:jackson-databind": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.dataformat:jackson-dataformat-cbor": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.dataformat:jackson-dataformat-smile": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.dataformat:jackson-dataformat-yaml": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.datatype:jackson-datatype-jdk8": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.datatype:jackson-datatype-joda": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.datatype:jackson-datatype-jsr310": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.module:jackson-module-afterburner": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common" - ], - "locked": "2.15.0" - }, - "com.github.ben-manes.caffeine:caffeine": { - "locked": "2.9.3" - }, - "com.google.protobuf:protobuf-java": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-common" - ], - "locked": "3.24.3" - }, - "com.jayway.jsonpath:json-path": { - "locked": "2.4.0" - }, - "com.netflix.conductor:conductor-annotations": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-common" - ], - "project": true - }, - "com.netflix.conductor:conductor-common": { - "project": true - }, - "com.netflix.spectator:spectator-api": { - "locked": "0.122.0" - }, - "com.spotify:completable-futures": { - "locked": "0.3.3" - }, - "commons-io:commons-io": { - "locked": "2.7" - }, - "io.reactivex:rxjava": { - "locked": "1.2.2" - }, - "jakarta.activation:jakarta.activation-api": { - "locked": "2.0.0" - }, - "jakarta.xml.bind:jakarta.xml.bind-api": { - "locked": "2.3.3" - }, - "org.apache.bval:bval-jsr": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-common" - ], - "locked": "2.0.6" - }, - "org.apache.commons:commons-lang3": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-common" - ], - "locked": "3.12.0" - }, - "org.apache.logging.log4j:log4j-api": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common" - ], - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-core": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common" - ], - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-jul": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common" - ], - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-slf4j-impl": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common" - ], - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-web": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common" - ], - "locked": "2.17.2" - }, - "org.openjdk.nashorn:nashorn-core": { - "locked": "15.4" - }, - "org.yaml:snakeyaml": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common" - ], - "locked": "2.0" - } - }, - "testCompileClasspath": { - "com.fasterxml.jackson.core:jackson-annotations": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.core:jackson-core": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.core:jackson-databind": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.dataformat:jackson-dataformat-cbor": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.dataformat:jackson-dataformat-smile": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.dataformat:jackson-dataformat-yaml": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.datatype:jackson-datatype-jdk8": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.datatype:jackson-datatype-joda": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.datatype:jackson-datatype-jsr310": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider": { - "locked": "2.15.0" - }, - "com.fasterxml.jackson.module:jackson-module-afterburner": { - "locked": "2.15.0" - }, - "com.github.ben-manes.caffeine:caffeine": { - "locked": "2.9.3" - }, - "com.google.protobuf:protobuf-java": { - "locked": "3.24.3" - }, - "com.jayway.jsonpath:json-path": { - "locked": "2.4.0" - }, - "com.netflix.conductor:conductor-common": { - "project": true - }, - "com.netflix.spectator:spectator-api": { - "locked": "0.122.0" - }, - "com.spotify:completable-futures": { - "locked": "0.3.3" - }, - "commons-io:commons-io": { - "locked": "2.7" - }, - "io.reactivex:rxjava": { - "locked": "1.2.2" - }, - "jakarta.activation:jakarta.activation-api": { - "locked": "2.0.0" - }, - "jakarta.xml.bind:jakarta.xml.bind-api": { - "locked": "2.3.3" - }, - "junit:junit": { - "locked": "4.13.2" - }, - "net.java.dev.jna:jna": { - "locked": "5.13.0" - }, - "org.apache.bval:bval-jsr": { - "locked": "2.0.6" - }, - "org.apache.commons:commons-lang3": { - "locked": "3.12.0" - }, - "org.apache.logging.log4j:log4j-api": { - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-core": { - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-jul": { - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-slf4j-impl": { - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-web": { - "locked": "2.17.2" - }, - "org.codehaus.groovy:groovy-all": { - "locked": "3.0.19" - }, - "org.glassfish.jaxb:jaxb-runtime": { - "locked": "2.3.3" - }, - "org.junit.vintage:junit-vintage-engine": { - "locked": "5.8.2" - }, - "org.openjdk.nashorn:nashorn-core": { - "locked": "15.4" - }, - "org.spockframework:spock-core": { - "locked": "2.3-groovy-3.0" - }, - "org.spockframework:spock-spring": { - "locked": "2.3-groovy-3.0" - }, - "org.springframework.boot:spring-boot-starter-log4j2": { - "locked": "2.7.16" - }, - "org.springframework.boot:spring-boot-starter-test": { - "locked": "2.7.16" - }, - "org.springframework.boot:spring-boot-starter-validation": { - "locked": "2.7.16" - }, - "org.springframework.retry:spring-retry": { - "locked": "1.3.4" - }, - "org.yaml:snakeyaml": { - "locked": "2.0" - } - }, - "testRuntimeClasspath": { - "com.fasterxml.jackson.core:jackson-annotations": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.core:jackson-core": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.core:jackson-databind": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.dataformat:jackson-dataformat-cbor": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.dataformat:jackson-dataformat-smile": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.dataformat:jackson-dataformat-yaml": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.datatype:jackson-datatype-jdk8": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.datatype:jackson-datatype-joda": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.datatype:jackson-datatype-jsr310": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common" - ], - "locked": "2.15.0" - }, - "com.fasterxml.jackson.module:jackson-module-afterburner": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common" - ], - "locked": "2.15.0" - }, - "com.github.ben-manes.caffeine:caffeine": { - "locked": "2.9.3" - }, - "com.google.protobuf:protobuf-java": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-common" - ], - "locked": "3.24.3" - }, - "com.jayway.jsonpath:json-path": { - "locked": "2.4.0" - }, - "com.netflix.conductor:conductor-annotations": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-common" - ], - "project": true - }, - "com.netflix.conductor:conductor-common": { - "project": true - }, - "com.netflix.spectator:spectator-api": { - "locked": "0.122.0" - }, - "com.spotify:completable-futures": { - "locked": "0.3.3" - }, - "commons-io:commons-io": { - "locked": "2.7" - }, - "io.reactivex:rxjava": { - "locked": "1.2.2" - }, - "jakarta.activation:jakarta.activation-api": { - "locked": "2.0.0" - }, - "jakarta.xml.bind:jakarta.xml.bind-api": { - "locked": "2.3.3" - }, - "junit:junit": { - "locked": "4.13.2" - }, - "net.java.dev.jna:jna": { - "locked": "5.13.0" - }, - "org.apache.bval:bval-jsr": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-common" - ], - "locked": "2.0.6" - }, - "org.apache.commons:commons-lang3": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-common" - ], - "locked": "3.12.0" - }, - "org.apache.logging.log4j:log4j-api": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common" - ], - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-core": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common" - ], - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-jul": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common" - ], - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-slf4j-impl": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common" - ], - "locked": "2.17.2" - }, - "org.apache.logging.log4j:log4j-web": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common" - ], - "locked": "2.17.2" - }, - "org.codehaus.groovy:groovy-all": { - "locked": "3.0.19" - }, - "org.glassfish.jaxb:jaxb-runtime": { - "locked": "2.3.3" - }, - "org.junit.vintage:junit-vintage-engine": { - "locked": "5.8.2" - }, - "org.openjdk.nashorn:nashorn-core": { - "locked": "15.4" - }, - "org.spockframework:spock-core": { - "locked": "2.3-groovy-3.0" - }, - "org.spockframework:spock-spring": { - "locked": "2.3-groovy-3.0" - }, - "org.springframework.boot:spring-boot-starter-log4j2": { - "locked": "2.7.16" - }, - "org.springframework.boot:spring-boot-starter-test": { - "locked": "2.7.16" - }, - "org.springframework.boot:spring-boot-starter-validation": { - "locked": "2.7.16" - }, - "org.springframework.retry:spring-retry": { - "locked": "1.3.4" - }, - "org.yaml:snakeyaml": { - "firstLevelTransitive": [ - "com.netflix.conductor:conductor-annotations", - "com.netflix.conductor:conductor-common" - ], - "locked": "2.0" - } - } -} \ No newline at end of file diff --git a/core/src/main/java/com/netflix/conductor/annotations/Audit.java b/core/src/main/java/com/netflix/conductor/annotations/Audit.java index 6f1d47199..3e55d7804 100644 --- a/core/src/main/java/com/netflix/conductor/annotations/Audit.java +++ b/core/src/main/java/com/netflix/conductor/annotations/Audit.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/core/src/main/java/com/netflix/conductor/annotations/Trace.java b/core/src/main/java/com/netflix/conductor/annotations/Trace.java index 61da42cc4..cf2b9ec5e 100644 --- a/core/src/main/java/com/netflix/conductor/annotations/Trace.java +++ b/core/src/main/java/com/netflix/conductor/annotations/Trace.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/core/src/main/java/com/netflix/conductor/annotations/VisibleForTesting.java b/core/src/main/java/com/netflix/conductor/annotations/VisibleForTesting.java index 492931128..fb1ae76b6 100644 --- a/core/src/main/java/com/netflix/conductor/annotations/VisibleForTesting.java +++ b/core/src/main/java/com/netflix/conductor/annotations/VisibleForTesting.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/core/src/main/java/com/netflix/conductor/core/LifecycleAwareComponent.java b/core/src/main/java/com/netflix/conductor/core/LifecycleAwareComponent.java index bfe1455fb..153cea1fb 100644 --- a/core/src/main/java/com/netflix/conductor/core/LifecycleAwareComponent.java +++ b/core/src/main/java/com/netflix/conductor/core/LifecycleAwareComponent.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/core/src/main/java/com/netflix/conductor/core/WorkflowContext.java b/core/src/main/java/com/netflix/conductor/core/WorkflowContext.java index d870761c5..559506dad 100644 --- a/core/src/main/java/com/netflix/conductor/core/WorkflowContext.java +++ b/core/src/main/java/com/netflix/conductor/core/WorkflowContext.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/core/src/main/java/com/netflix/conductor/core/config/ConductorCoreConfiguration.java b/core/src/main/java/com/netflix/conductor/core/config/ConductorCoreConfiguration.java index a09403d5f..c0e8de9ee 100644 --- a/core/src/main/java/com/netflix/conductor/core/config/ConductorCoreConfiguration.java +++ b/core/src/main/java/com/netflix/conductor/core/config/ConductorCoreConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2021 Netflix, Inc. + * Copyright 2021 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/core/src/main/java/com/netflix/conductor/core/config/ConductorProperties.java b/core/src/main/java/com/netflix/conductor/core/config/ConductorProperties.java index c54b7a9de..b1bfb4adb 100644 --- a/core/src/main/java/com/netflix/conductor/core/config/ConductorProperties.java +++ b/core/src/main/java/com/netflix/conductor/core/config/ConductorProperties.java @@ -1,5 +1,5 @@ /* - * Copyright 2021 Netflix, Inc. + * Copyright 2021 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at @@ -81,6 +81,9 @@ public class ConductorProperties { @DurationUnit(ChronoUnit.SECONDS) private Duration taskExecutionPostponeDuration = Duration.ofSeconds(60); + /** Used to enable/disable the indexing of tasks. */ + private boolean taskIndexingEnabled = true; + /** Used to enable/disable the indexing of task execution logs. */ private boolean taskExecLogIndexingEnabled = true; @@ -333,6 +336,14 @@ public void setTaskExecLogIndexingEnabled(boolean taskExecLogIndexingEnabled) { this.taskExecLogIndexingEnabled = taskExecLogIndexingEnabled; } + public boolean isTaskIndexingEnabled() { + return taskIndexingEnabled; + } + + public void setTaskIndexingEnabled(boolean taskIndexingEnabled) { + this.taskIndexingEnabled = taskIndexingEnabled; + } + public boolean isAsyncIndexingEnabled() { return asyncIndexingEnabled; } diff --git a/core/src/main/java/com/netflix/conductor/core/config/SchedulerConfiguration.java b/core/src/main/java/com/netflix/conductor/core/config/SchedulerConfiguration.java index 364406e10..b63366649 100644 --- a/core/src/main/java/com/netflix/conductor/core/config/SchedulerConfiguration.java +++ b/core/src/main/java/com/netflix/conductor/core/config/SchedulerConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2021 Netflix, Inc. + * Copyright 2021 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/core/src/main/java/com/netflix/conductor/core/dal/ExecutionDAOFacade.java b/core/src/main/java/com/netflix/conductor/core/dal/ExecutionDAOFacade.java index d88150005..3180dfc5b 100644 --- a/core/src/main/java/com/netflix/conductor/core/dal/ExecutionDAOFacade.java +++ b/core/src/main/java/com/netflix/conductor/core/dal/ExecutionDAOFacade.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at @@ -21,8 +21,6 @@ import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; -import javax.annotation.PreDestroy; - import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -52,6 +50,7 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; +import jakarta.annotation.PreDestroy; import static com.netflix.conductor.core.utils.Utils.DECIDER_QUEUE; @@ -440,11 +439,15 @@ public List createTasks(List tasks) { } public List getTasksForWorkflow(String workflowId) { - return executionDAO.getTasksForWorkflow(workflowId).stream() + return getTaskModelsForWorkflow(workflowId).stream() .map(TaskModel::toTask) .collect(Collectors.toList()); } + public List getTaskModelsForWorkflow(String workflowId) { + return executionDAO.getTasksForWorkflow(workflowId); + } + public TaskModel getTaskModel(String taskId) { TaskModel taskModel = getTaskFromDatastore(taskId); if (taskModel != null) { @@ -510,7 +513,7 @@ public void updateTask(TaskModel taskModel) { * of tasks on a system failure. So only index for each update if async indexing is not enabled. * If it *is* enabled, tasks will be indexed only when a workflow is in terminal state. */ - if (!properties.isAsyncIndexingEnabled()) { + if (!properties.isAsyncIndexingEnabled() && properties.isTaskIndexingEnabled()) { indexDAO.indexTask(new TaskSummary(taskModel.toTask())); } } catch (TerminateWorkflowException e) { diff --git a/core/src/main/java/com/netflix/conductor/core/event/WorkflowCreationEvent.java b/core/src/main/java/com/netflix/conductor/core/event/WorkflowCreationEvent.java index 28c4fca72..c6d7085ef 100644 --- a/core/src/main/java/com/netflix/conductor/core/event/WorkflowCreationEvent.java +++ b/core/src/main/java/com/netflix/conductor/core/event/WorkflowCreationEvent.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/core/src/main/java/com/netflix/conductor/core/event/WorkflowEvaluationEvent.java b/core/src/main/java/com/netflix/conductor/core/event/WorkflowEvaluationEvent.java index 2b139636c..267224b56 100644 --- a/core/src/main/java/com/netflix/conductor/core/event/WorkflowEvaluationEvent.java +++ b/core/src/main/java/com/netflix/conductor/core/event/WorkflowEvaluationEvent.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/core/src/main/java/com/netflix/conductor/core/events/ActionProcessor.java b/core/src/main/java/com/netflix/conductor/core/events/ActionProcessor.java index 6b8139652..83e60fbb8 100644 --- a/core/src/main/java/com/netflix/conductor/core/events/ActionProcessor.java +++ b/core/src/main/java/com/netflix/conductor/core/events/ActionProcessor.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/core/src/main/java/com/netflix/conductor/core/events/DefaultEventProcessor.java b/core/src/main/java/com/netflix/conductor/core/events/DefaultEventProcessor.java index fa7f1725b..dbdbf6b15 100644 --- a/core/src/main/java/com/netflix/conductor/core/events/DefaultEventProcessor.java +++ b/core/src/main/java/com/netflix/conductor/core/events/DefaultEventProcessor.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/core/src/main/java/com/netflix/conductor/core/events/DefaultEventQueueManager.java b/core/src/main/java/com/netflix/conductor/core/events/DefaultEventQueueManager.java index 862287cac..a83755069 100644 --- a/core/src/main/java/com/netflix/conductor/core/events/DefaultEventQueueManager.java +++ b/core/src/main/java/com/netflix/conductor/core/events/DefaultEventQueueManager.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/core/src/main/java/com/netflix/conductor/core/events/EventQueueManager.java b/core/src/main/java/com/netflix/conductor/core/events/EventQueueManager.java index fc6a568f6..7580af79c 100644 --- a/core/src/main/java/com/netflix/conductor/core/events/EventQueueManager.java +++ b/core/src/main/java/com/netflix/conductor/core/events/EventQueueManager.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/core/src/main/java/com/netflix/conductor/core/events/EventQueueProvider.java b/core/src/main/java/com/netflix/conductor/core/events/EventQueueProvider.java index 8bd11f929..22e3cecc3 100644 --- a/core/src/main/java/com/netflix/conductor/core/events/EventQueueProvider.java +++ b/core/src/main/java/com/netflix/conductor/core/events/EventQueueProvider.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/core/src/main/java/com/netflix/conductor/core/events/EventQueues.java b/core/src/main/java/com/netflix/conductor/core/events/EventQueues.java index b4ab2e388..139aad0c4 100644 --- a/core/src/main/java/com/netflix/conductor/core/events/EventQueues.java +++ b/core/src/main/java/com/netflix/conductor/core/events/EventQueues.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at @@ -18,7 +18,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.lang.NonNull; import org.springframework.stereotype.Component; @@ -37,7 +36,6 @@ public class EventQueues { private final ParametersUtils parametersUtils; private final Map providers; - @Autowired public EventQueues( @Qualifier(EVENT_QUEUE_PROVIDERS_QUALIFIER) Map providers, ParametersUtils parametersUtils) { diff --git a/core/src/main/java/com/netflix/conductor/core/events/ScriptEvaluator.java b/core/src/main/java/com/netflix/conductor/core/events/ScriptEvaluator.java index dc46354b0..c77f3860d 100644 --- a/core/src/main/java/com/netflix/conductor/core/events/ScriptEvaluator.java +++ b/core/src/main/java/com/netflix/conductor/core/events/ScriptEvaluator.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at @@ -17,6 +17,8 @@ import javax.script.ScriptEngineManager; import javax.script.ScriptException; +import org.openjdk.nashorn.api.scripting.NashornScriptEngineFactory; + public class ScriptEvaluator { private static ScriptEngine engine; @@ -25,7 +27,7 @@ private ScriptEvaluator() {} /** * Evaluates the script with the help of input provided but converts the result to a boolean - * value. + * value. Set environment variable CONDUCTOR_NASHORN_ES6_ENABLED=true for Nashorn ES6 support. * * @param script Script to be evaluated. * @param input Input parameters. @@ -37,7 +39,8 @@ public static Boolean evalBool(String script, Object input) throws ScriptExcepti } /** - * Evaluates the script with the help of input provided. + * Evaluates the script with the help of input provided. Set environment variable + * CONDUCTOR_NASHORN_ES6_ENABLED=true for Nashorn ES6 support. * * @param script Script to be evaluated. * @param input Input parameters. @@ -45,16 +48,30 @@ public static Boolean evalBool(String script, Object input) throws ScriptExcepti * @return Generic object, the result of the evaluated expression. */ public static Object eval(String script, Object input) throws ScriptException { - if (engine == null) { - engine = new ScriptEngineManager().getEngineByName("Nashorn"); + initEngine(false); + Bindings bindings = engine.createBindings(); + bindings.put("$", input); + return engine.eval(script, bindings); + } + + // to mock in a test + public static String getEnv(String name) { + return System.getenv(name); + } + + public static void initEngine(boolean reInit) { + if (engine == null || reInit) { + if ("true".equalsIgnoreCase(getEnv("CONDUCTOR_NASHORN_ES6_ENABLED"))) { + NashornScriptEngineFactory factory = new NashornScriptEngineFactory(); + engine = factory.getScriptEngine("--language=es6"); + } else { + engine = new ScriptEngineManager().getEngineByName("Nashorn"); + } } if (engine == null) { throw new RuntimeException( "missing nashorn engine. Ensure you are running supported JVM"); } - Bindings bindings = engine.createBindings(); - bindings.put("$", input); - return engine.eval(script, bindings); } /** diff --git a/core/src/main/java/com/netflix/conductor/core/events/SimpleActionProcessor.java b/core/src/main/java/com/netflix/conductor/core/events/SimpleActionProcessor.java index 27b81edf7..a91bcad43 100644 --- a/core/src/main/java/com/netflix/conductor/core/events/SimpleActionProcessor.java +++ b/core/src/main/java/com/netflix/conductor/core/events/SimpleActionProcessor.java @@ -1,5 +1,5 @@ /* - * Copyright 2020 Netflix, Inc. + * Copyright 2020 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/core/src/main/java/com/netflix/conductor/core/events/queue/ConductorEventQueueProvider.java b/core/src/main/java/com/netflix/conductor/core/events/queue/ConductorEventQueueProvider.java index 76e530101..478a8d7b2 100644 --- a/core/src/main/java/com/netflix/conductor/core/events/queue/ConductorEventQueueProvider.java +++ b/core/src/main/java/com/netflix/conductor/core/events/queue/ConductorEventQueueProvider.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/core/src/main/java/com/netflix/conductor/core/events/queue/ConductorObservableQueue.java b/core/src/main/java/com/netflix/conductor/core/events/queue/ConductorObservableQueue.java index 649cc7b50..e4689423d 100644 --- a/core/src/main/java/com/netflix/conductor/core/events/queue/ConductorObservableQueue.java +++ b/core/src/main/java/com/netflix/conductor/core/events/queue/ConductorObservableQueue.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/core/src/main/java/com/netflix/conductor/core/events/queue/DefaultEventQueueProcessor.java b/core/src/main/java/com/netflix/conductor/core/events/queue/DefaultEventQueueProcessor.java index f1c508803..ff49a173f 100644 --- a/core/src/main/java/com/netflix/conductor/core/events/queue/DefaultEventQueueProcessor.java +++ b/core/src/main/java/com/netflix/conductor/core/events/queue/DefaultEventQueueProcessor.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/core/src/main/java/com/netflix/conductor/core/events/queue/Message.java b/core/src/main/java/com/netflix/conductor/core/events/queue/Message.java index b7d33961f..edefe53af 100644 --- a/core/src/main/java/com/netflix/conductor/core/events/queue/Message.java +++ b/core/src/main/java/com/netflix/conductor/core/events/queue/Message.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/core/src/main/java/com/netflix/conductor/core/events/queue/ObservableQueue.java b/core/src/main/java/com/netflix/conductor/core/events/queue/ObservableQueue.java index ecdc75921..ac5098ea7 100644 --- a/core/src/main/java/com/netflix/conductor/core/events/queue/ObservableQueue.java +++ b/core/src/main/java/com/netflix/conductor/core/events/queue/ObservableQueue.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/core/src/main/java/com/netflix/conductor/core/exception/ConflictException.java b/core/src/main/java/com/netflix/conductor/core/exception/ConflictException.java index 7c718ed59..21cbd6071 100644 --- a/core/src/main/java/com/netflix/conductor/core/exception/ConflictException.java +++ b/core/src/main/java/com/netflix/conductor/core/exception/ConflictException.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/core/src/main/java/com/netflix/conductor/core/exception/NonTransientException.java b/core/src/main/java/com/netflix/conductor/core/exception/NonTransientException.java index 4af05633f..0bf93d14d 100644 --- a/core/src/main/java/com/netflix/conductor/core/exception/NonTransientException.java +++ b/core/src/main/java/com/netflix/conductor/core/exception/NonTransientException.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/core/src/main/java/com/netflix/conductor/core/exception/NotFoundException.java b/core/src/main/java/com/netflix/conductor/core/exception/NotFoundException.java index a89b7beed..03f4d1d5c 100644 --- a/core/src/main/java/com/netflix/conductor/core/exception/NotFoundException.java +++ b/core/src/main/java/com/netflix/conductor/core/exception/NotFoundException.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/core/src/main/java/com/netflix/conductor/core/exception/TerminateWorkflowException.java b/core/src/main/java/com/netflix/conductor/core/exception/TerminateWorkflowException.java index 366c4864f..aa8ec4a50 100644 --- a/core/src/main/java/com/netflix/conductor/core/exception/TerminateWorkflowException.java +++ b/core/src/main/java/com/netflix/conductor/core/exception/TerminateWorkflowException.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/core/src/main/java/com/netflix/conductor/core/exception/TransientException.java b/core/src/main/java/com/netflix/conductor/core/exception/TransientException.java index 87cc9d852..c6e536b15 100644 --- a/core/src/main/java/com/netflix/conductor/core/exception/TransientException.java +++ b/core/src/main/java/com/netflix/conductor/core/exception/TransientException.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/core/src/main/java/com/netflix/conductor/core/execution/AsyncSystemTaskExecutor.java b/core/src/main/java/com/netflix/conductor/core/execution/AsyncSystemTaskExecutor.java index 331a2b4ac..8751f1582 100644 --- a/core/src/main/java/com/netflix/conductor/core/execution/AsyncSystemTaskExecutor.java +++ b/core/src/main/java/com/netflix/conductor/core/execution/AsyncSystemTaskExecutor.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/core/src/main/java/com/netflix/conductor/core/execution/DeciderService.java b/core/src/main/java/com/netflix/conductor/core/execution/DeciderService.java index c6bf486ba..e1bacb34d 100644 --- a/core/src/main/java/com/netflix/conductor/core/execution/DeciderService.java +++ b/core/src/main/java/com/netflix/conductor/core/execution/DeciderService.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at @@ -207,7 +207,9 @@ private DeciderOutcome decide(final WorkflowModel workflow, List preS tasksToBeScheduled.put(retryTask.get().getReferenceTaskName(), retryTask.get()); executedTaskRefNames.remove(retryTask.get().getReferenceTaskName()); outcome.tasksToBeUpdated.add(pendingTask); - } else { + } else if (!(pendingTask.getWorkflowTask() != null + && pendingTask.getWorkflowTask().isPermissive() + && !pendingTask.getWorkflowTask().isOptional())) { pendingTask.setStatus(COMPLETED_WITH_ERRORS); } } @@ -254,6 +256,39 @@ private DeciderOutcome decide(final WorkflowModel workflow, List preS if (hasSuccessfulTerminateTask || (outcome.tasksToBeScheduled.isEmpty() && checkForWorkflowCompletion(workflow))) { LOGGER.debug("Marking workflow: {} as complete.", workflow); + List permissiveTasksTerminalNonSuccessful = + workflow.getTasks().stream() + .filter(t -> t.getWorkflowTask() != null) + .filter(t -> t.getWorkflowTask().isPermissive()) + .filter(t -> !t.getWorkflowTask().isOptional()) + .collect( + Collectors.toMap( + TaskModel::getReferenceTaskName, + t -> t, + (t1, t2) -> + t1.getRetryCount() > t2.getRetryCount() + ? t1 + : t2)) + .values() + .stream() + .filter( + t -> + t.getStatus().isTerminal() + && !t.getStatus().isSuccessful()) + .toList(); + if (!permissiveTasksTerminalNonSuccessful.isEmpty()) { + final String errMsg = + permissiveTasksTerminalNonSuccessful.stream() + .map( + t -> + String.format( + "Task %s failed with status: %s and reason: '%s'", + t.getTaskId(), + t.getStatus(), + t.getReasonForIncompletion())) + .collect(Collectors.joining(". ")); + throw new TerminateWorkflowException(errMsg); + } outcome.isComplete = true; } @@ -437,11 +472,6 @@ public boolean checkForWorkflowCompletion(final WorkflowModel workflow) if (status == null || !status.isTerminal()) { return false; } - // if we reach here, the task has been completed. - // Was the task successful in completion? - if (!status.isSuccessful()) { - return false; - } } boolean noPendingSchedule = @@ -529,7 +559,8 @@ Optional retry( if (!task.getStatus().isRetriable() || TaskType.isBuiltIn(task.getTaskType()) || expectedRetryCount <= retryCount) { - if (workflowTask != null && workflowTask.isOptional()) { + if (workflowTask != null + && (workflowTask.isOptional() || workflowTask.isPermissive())) { return Optional.empty(); } WorkflowModel.Status status; diff --git a/core/src/main/java/com/netflix/conductor/core/execution/StartWorkflowInput.java b/core/src/main/java/com/netflix/conductor/core/execution/StartWorkflowInput.java index 7eb8fb93d..f24ea2771 100644 --- a/core/src/main/java/com/netflix/conductor/core/execution/StartWorkflowInput.java +++ b/core/src/main/java/com/netflix/conductor/core/execution/StartWorkflowInput.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/core/src/main/java/com/netflix/conductor/core/execution/WorkflowExecutor.java b/core/src/main/java/com/netflix/conductor/core/execution/WorkflowExecutor.java index 6070741a2..c35547a69 100644 --- a/core/src/main/java/com/netflix/conductor/core/execution/WorkflowExecutor.java +++ b/core/src/main/java/com/netflix/conductor/core/execution/WorkflowExecutor.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at @@ -336,6 +336,18 @@ private void retry(WorkflowModel workflow) { for (TaskModel task : workflow.getTasks()) { switch (task.getStatus()) { case FAILED: + if (task.getTaskType().equalsIgnoreCase(TaskType.JOIN.toString()) + || task.getTaskType() + .equalsIgnoreCase(TaskType.EXCLUSIVE_JOIN.toString())) { + @SuppressWarnings("unchecked") + List joinOn = (List) task.getInputData().get("joinOn"); + boolean joinOnFailedPermissive = isJoinOnFailedPermissive(joinOn, workflow); + if (joinOnFailedPermissive) { + task.setStatus(IN_PROGRESS); + addTaskToQueue(task); + break; + } + } case FAILED_WITH_TERMINAL_ERROR: case TIMED_OUT: retriableMap.put(task.getReferenceTaskName(), task); @@ -1191,6 +1203,15 @@ List cancelNonTerminalTasks(WorkflowModel workflow) { if (!task.getStatus().isTerminal()) { // Cancel the ones which are not completed yet.... task.setStatus(CANCELED); + try { + notifyTaskStatusListener(task); + } catch (Exception e) { + String errorMsg = + String.format( + "Error while notifying TaskStatusListener: %s for workflow: %s", + task.getTaskId(), task.getWorkflowInstanceId()); + LOGGER.error(errorMsg, e); + } if (systemTaskRegistry.isSystemTask(task.getTaskType())) { WorkflowSystemTask workflowSystemTask = systemTaskRegistry.get(task.getTaskType()); @@ -1814,4 +1835,14 @@ private void expediteLazyWorkflowEvaluation(String workflowId) { LOGGER.info("Pushed workflow {} to {} for expedited evaluation", workflowId, DECIDER_QUEUE); } + + private static boolean isJoinOnFailedPermissive(List joinOn, WorkflowModel workflow) { + return joinOn.stream() + .map(workflow::getTaskByRefName) + .anyMatch( + t -> + t.getWorkflowTask().isPermissive() + && !t.getWorkflowTask().isOptional() + && t.getStatus().equals(FAILED)); + } } diff --git a/core/src/main/java/com/netflix/conductor/core/execution/evaluators/Evaluator.java b/core/src/main/java/com/netflix/conductor/core/execution/evaluators/Evaluator.java index 88d01ef7f..13bce2b24 100644 --- a/core/src/main/java/com/netflix/conductor/core/execution/evaluators/Evaluator.java +++ b/core/src/main/java/com/netflix/conductor/core/execution/evaluators/Evaluator.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/core/src/main/java/com/netflix/conductor/core/execution/evaluators/JavascriptEvaluator.java b/core/src/main/java/com/netflix/conductor/core/execution/evaluators/JavascriptEvaluator.java index 8f2de942d..4a22bdbe9 100644 --- a/core/src/main/java/com/netflix/conductor/core/execution/evaluators/JavascriptEvaluator.java +++ b/core/src/main/java/com/netflix/conductor/core/execution/evaluators/JavascriptEvaluator.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/core/src/main/java/com/netflix/conductor/core/execution/evaluators/ValueParamEvaluator.java b/core/src/main/java/com/netflix/conductor/core/execution/evaluators/ValueParamEvaluator.java index f1fda6178..94c34b0d0 100644 --- a/core/src/main/java/com/netflix/conductor/core/execution/evaluators/ValueParamEvaluator.java +++ b/core/src/main/java/com/netflix/conductor/core/execution/evaluators/ValueParamEvaluator.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/core/src/main/java/com/netflix/conductor/core/execution/mapper/DecisionTaskMapper.java b/core/src/main/java/com/netflix/conductor/core/execution/mapper/DecisionTaskMapper.java index d3f494f3b..4ac394de8 100644 --- a/core/src/main/java/com/netflix/conductor/core/execution/mapper/DecisionTaskMapper.java +++ b/core/src/main/java/com/netflix/conductor/core/execution/mapper/DecisionTaskMapper.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/core/src/main/java/com/netflix/conductor/core/execution/mapper/DoWhileTaskMapper.java b/core/src/main/java/com/netflix/conductor/core/execution/mapper/DoWhileTaskMapper.java index 66e6978d7..054d854de 100644 --- a/core/src/main/java/com/netflix/conductor/core/execution/mapper/DoWhileTaskMapper.java +++ b/core/src/main/java/com/netflix/conductor/core/execution/mapper/DoWhileTaskMapper.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at @@ -18,7 +18,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import com.netflix.conductor.common.metadata.tasks.TaskDef; @@ -42,7 +41,6 @@ public class DoWhileTaskMapper implements TaskMapper { private final MetadataDAO metadataDAO; private final ParametersUtils parametersUtils; - @Autowired public DoWhileTaskMapper(MetadataDAO metadataDAO, ParametersUtils parametersUtils) { this.metadataDAO = metadataDAO; this.parametersUtils = parametersUtils; diff --git a/core/src/main/java/com/netflix/conductor/core/execution/mapper/DynamicTaskMapper.java b/core/src/main/java/com/netflix/conductor/core/execution/mapper/DynamicTaskMapper.java index a669cc33c..4ab0480d8 100644 --- a/core/src/main/java/com/netflix/conductor/core/execution/mapper/DynamicTaskMapper.java +++ b/core/src/main/java/com/netflix/conductor/core/execution/mapper/DynamicTaskMapper.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at @@ -19,7 +19,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import com.netflix.conductor.annotations.VisibleForTesting; @@ -46,7 +45,6 @@ public class DynamicTaskMapper implements TaskMapper { private final ParametersUtils parametersUtils; private final MetadataDAO metadataDAO; - @Autowired public DynamicTaskMapper(ParametersUtils parametersUtils, MetadataDAO metadataDAO) { this.parametersUtils = parametersUtils; this.metadataDAO = metadataDAO; diff --git a/core/src/main/java/com/netflix/conductor/core/execution/mapper/EventTaskMapper.java b/core/src/main/java/com/netflix/conductor/core/execution/mapper/EventTaskMapper.java index c65423a59..0ec323530 100644 --- a/core/src/main/java/com/netflix/conductor/core/execution/mapper/EventTaskMapper.java +++ b/core/src/main/java/com/netflix/conductor/core/execution/mapper/EventTaskMapper.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at @@ -17,7 +17,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import com.netflix.conductor.common.metadata.tasks.TaskType; @@ -35,7 +34,6 @@ public class EventTaskMapper implements TaskMapper { private final ParametersUtils parametersUtils; - @Autowired public EventTaskMapper(ParametersUtils parametersUtils) { this.parametersUtils = parametersUtils; } diff --git a/core/src/main/java/com/netflix/conductor/core/execution/mapper/ExclusiveJoinTaskMapper.java b/core/src/main/java/com/netflix/conductor/core/execution/mapper/ExclusiveJoinTaskMapper.java index dc648f015..587460cf9 100644 --- a/core/src/main/java/com/netflix/conductor/core/execution/mapper/ExclusiveJoinTaskMapper.java +++ b/core/src/main/java/com/netflix/conductor/core/execution/mapper/ExclusiveJoinTaskMapper.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/core/src/main/java/com/netflix/conductor/core/execution/mapper/ForkJoinDynamicTaskMapper.java b/core/src/main/java/com/netflix/conductor/core/execution/mapper/ForkJoinDynamicTaskMapper.java index 8d9126df8..113f9b41d 100644 --- a/core/src/main/java/com/netflix/conductor/core/execution/mapper/ForkJoinDynamicTaskMapper.java +++ b/core/src/main/java/com/netflix/conductor/core/execution/mapper/ForkJoinDynamicTaskMapper.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at @@ -25,15 +25,16 @@ import org.apache.commons.lang3.tuple.Pair; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import com.netflix.conductor.annotations.VisibleForTesting; import com.netflix.conductor.common.metadata.tasks.TaskType; import com.netflix.conductor.common.metadata.workflow.DynamicForkJoinTaskList; +import com.netflix.conductor.common.metadata.workflow.SubWorkflowParams; import com.netflix.conductor.common.metadata.workflow.WorkflowDef; import com.netflix.conductor.common.metadata.workflow.WorkflowTask; import com.netflix.conductor.core.exception.TerminateWorkflowException; +import com.netflix.conductor.core.execution.tasks.SystemTaskRegistry; import com.netflix.conductor.core.utils.IDGenerator; import com.netflix.conductor.core.utils.ParametersUtils; import com.netflix.conductor.dao.MetadataDAO; @@ -43,6 +44,9 @@ import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; +import static com.netflix.conductor.common.metadata.tasks.TaskType.SUB_WORKFLOW; +import static com.netflix.conductor.common.metadata.tasks.TaskType.TASK_TYPE_SIMPLE; + /** * An implementation of {@link TaskMapper} to map a {@link WorkflowTask} of type {@link * TaskType#FORK_JOIN_DYNAMIC} to a LinkedList of {@link TaskModel} beginning with a {@link @@ -58,19 +62,22 @@ public class ForkJoinDynamicTaskMapper implements TaskMapper { private final ParametersUtils parametersUtils; private final ObjectMapper objectMapper; private final MetadataDAO metadataDAO; + private final SystemTaskRegistry systemTaskRegistry; + private static final TypeReference> ListOfWorkflowTasks = new TypeReference<>() {}; - @Autowired public ForkJoinDynamicTaskMapper( IDGenerator idGenerator, ParametersUtils parametersUtils, ObjectMapper objectMapper, - MetadataDAO metadataDAO) { + MetadataDAO metadataDAO, + SystemTaskRegistry systemTaskRegistry) { this.idGenerator = idGenerator; this.parametersUtils = parametersUtils; this.objectMapper = objectMapper; this.metadataDAO = metadataDAO; + this.systemTaskRegistry = systemTaskRegistry; } @Override @@ -126,92 +133,123 @@ public List getMappedTasks(TaskMapperContext taskMapperContext) WorkflowTask workflowTask = taskMapperContext.getWorkflowTask(); WorkflowModel workflowModel = taskMapperContext.getWorkflowModel(); int retryCount = taskMapperContext.getRetryCount(); + Map input = + parametersUtils.getTaskInput( + workflowTask.getInputParameters(), workflowModel, null, null); List mappedTasks = new LinkedList<>(); // Get the list of dynamic tasks and the input for the tasks + Pair, Map>> workflowTasksAndInputPair = - Optional.ofNullable(workflowTask.getDynamicForkTasksParam()) - .map( - dynamicForkTaskParam -> - getDynamicForkTasksAndInput( - workflowTask, workflowModel, dynamicForkTaskParam)) - .orElseGet( - () -> getDynamicForkJoinTasksAndInput(workflowTask, workflowModel)); + getDynamicTasksSimple(workflowTask, input); + + if (workflowTasksAndInputPair == null) { + workflowTasksAndInputPair = + Optional.ofNullable(workflowTask.getDynamicForkTasksParam()) + .map( + dynamicForkTaskParam -> + getDynamicForkTasksAndInput( + workflowTask, + workflowModel, + dynamicForkTaskParam, + input)) + .orElseGet( + () -> + getDynamicForkJoinTasksAndInput( + workflowTask, workflowModel, input)); + } List dynForkTasks = workflowTasksAndInputPair.getLeft(); Map> tasksInput = workflowTasksAndInputPair.getRight(); // Create Fork Task which needs to be followed by the dynamic tasks TaskModel forkDynamicTask = createDynamicForkTask(taskMapperContext, dynForkTasks); + forkDynamicTask.getInputData().putAll(taskMapperContext.getTaskInput()); mappedTasks.add(forkDynamicTask); + Optional exists = + workflowModel.getTasks().stream() + .filter( + task -> + task.getReferenceTaskName() + .equals( + taskMapperContext + .getWorkflowTask() + .getTaskReferenceName())) + .findAny(); List joinOnTaskRefs = new LinkedList<>(); // Add each dynamic task to the mapped tasks and also get the last dynamic task in the list, // which indicates that the following task after that needs to be a join task - for (WorkflowTask dynForkTask : - dynForkTasks) { // TODO this is a cyclic dependency, break it out using function - // composition - List forkedTasks = - taskMapperContext - .getDeciderService() - .getTasksToBeScheduled(workflowModel, dynForkTask, retryCount); - - // It's an error state if no forkedTasks can be decided upon. In the cases where we've - // seen - // this happen is when a dynamic task is attempting to be created here, but a task with - // the - // same reference name has already been created in the Workflow. - if (forkedTasks == null || forkedTasks.isEmpty()) { - Optional existingTaskRefName = - workflowModel.getTasks().stream() - .filter( - runningTask -> - runningTask - .getStatus() - .equals( - TaskModel.Status - .IN_PROGRESS) - || runningTask.getStatus().isTerminal()) - .map(TaskModel::getReferenceTaskName) - .filter( - refTaskName -> - refTaskName.equals( - dynForkTask.getTaskReferenceName())) - .findAny(); - - // Construct an informative error message - String terminateMessage = - "No dynamic tasks could be created for the Workflow: " - + workflowModel.toShortString() - + ", Dynamic Fork Task: " - + dynForkTask; - if (existingTaskRefName.isPresent()) { - terminateMessage += - "Attempted to create a duplicate task reference name: " - + existingTaskRefName.get(); + if (!exists.isPresent()) { + // Add each dynamic task to the mapped tasks and also get the last dynamic task in the + // list, + // which indicates that the following task after that needs to be a join task + for (WorkflowTask dynForkTask : dynForkTasks) { + // composition + + List forkedTasks = + taskMapperContext + .getDeciderService() + .getTasksToBeScheduled(workflowModel, dynForkTask, retryCount); + if (forkedTasks == null || forkedTasks.isEmpty()) { + Optional existingTaskRefName = + workflowModel.getTasks().stream() + .filter( + runningTask -> + runningTask + .getStatus() + .equals( + TaskModel.Status + .IN_PROGRESS) + || runningTask.getStatus().isTerminal()) + .map(TaskModel::getReferenceTaskName) + .filter( + refTaskName -> + refTaskName.equals( + dynForkTask.getTaskReferenceName())) + .findAny(); + + // Construct an informative error message + String terminateMessage = + "No dynamic tasks could be created for the Workflow: " + + workflowModel.toShortString() + + ", Dynamic Fork Task: " + + dynForkTask; + if (existingTaskRefName.isPresent()) { + terminateMessage += + " attempted to create a duplicate task reference name: " + + existingTaskRefName.get(); + } + throw new TerminateWorkflowException(terminateMessage); } - throw new TerminateWorkflowException(terminateMessage); - } - for (TaskModel forkedTask : forkedTasks) { - try { - Map forkedTaskInput = - tasksInput.get(forkedTask.getReferenceTaskName()); - forkedTask.addInput(forkedTaskInput); - } catch (Exception e) { - String reason = - String.format( - "Tasks could not be dynamically forked due to invalid input: %s", - e.getMessage()); - throw new TerminateWorkflowException(reason); + for (TaskModel forkedTask : forkedTasks) { + try { + Map forkedTaskInput = + tasksInput.get(forkedTask.getReferenceTaskName()); + if (forkedTask.getInputData() == null) { + forkedTask.setInputData(new HashMap<>()); + } + if (forkedTaskInput == null) { + forkedTaskInput = new HashMap<>(); + } + forkedTask.getInputData().putAll(forkedTaskInput); + } catch (Exception e) { + String reason = + String.format( + "Tasks could not be dynamically forked due to invalid input: %s", + e.getMessage()); + throw new TerminateWorkflowException(reason); + } } + mappedTasks.addAll(forkedTasks); + // Get the last of the dynamic tasks so that the join can be performed once this + // task is + // done + TaskModel last = forkedTasks.get(forkedTasks.size() - 1); + joinOnTaskRefs.add(last.getReferenceTaskName()); } - mappedTasks.addAll(forkedTasks); - // Get the last of the dynamic tasks so that the join can be performed once this task is - // done - TaskModel last = forkedTasks.get(forkedTasks.size() - 1); - joinOnTaskRefs.add(last.getReferenceTaskName()); } // From the workflow definition get the next task and make sure that it is a JOIN task. @@ -319,15 +357,14 @@ TaskModel createJoinTask( @SuppressWarnings("unchecked") @VisibleForTesting Pair, Map>> getDynamicForkTasksAndInput( - WorkflowTask workflowTask, WorkflowModel workflowModel, String dynamicForkTaskParam) + WorkflowTask workflowTask, + WorkflowModel workflowModel, + String dynamicForkTaskParam, + Map input) throws TerminateWorkflowException { - Map input = - parametersUtils.getTaskInput( - workflowTask.getInputParameters(), workflowModel, null, null); - Object dynamicForkTasksJson = input.get(dynamicForkTaskParam); List dynamicForkWorkflowTasks = - objectMapper.convertValue(dynamicForkTasksJson, ListOfWorkflowTasks); + getDynamicForkWorkflowTasks(dynamicForkTaskParam, input); if (dynamicForkWorkflowTasks == null) { dynamicForkWorkflowTasks = new ArrayList<>(); } @@ -348,6 +385,144 @@ Pair, Map>> getDynamicForkTasksAn dynamicForkWorkflowTasks, (Map>) dynamicForkTasksInput); } + private List getDynamicForkWorkflowTasks( + String dynamicForkTaskParam, Map input) { + Object dynamicForkTasksJson = input.get(dynamicForkTaskParam); + try { + List tasks = + objectMapper.convertValue(dynamicForkTasksJson, ListOfWorkflowTasks); + for (var task : tasks) { + if (task.getTaskReferenceName() == null) { + throw new RuntimeException( + "One of the tasks had a null/missing taskReferenceName"); + } + } + return tasks; + } catch (Exception e) { + LOGGER.warn("IllegalArgumentException in getDynamicForkTasksAndInput", e); + throw new TerminateWorkflowException( + String.format( + "Input '%s' is invalid. Cannot deserialize a list of Workflow Tasks from '%s'", + dynamicForkTaskParam, dynamicForkTasksJson)); + } + } + + Pair, Map>> getDynamicTasksSimple( + WorkflowTask workflowTask, Map input) + throws TerminateWorkflowException { + + String forkSubWorkflowName = (String) input.get("forkTaskWorkflow"); + String forkSubWorkflowVersionStr = (String) input.get("forkTaskWorkflowVersion"); + Integer forkSubWorkflowVersion = null; + try { + forkSubWorkflowVersion = Integer.parseInt(forkSubWorkflowVersionStr); + } catch (NumberFormatException nfe) { + } + + String forkTaskType = (String) input.get("forkTaskType"); + String forkTaskName = (String) input.get("forkTaskName"); + if (forkTaskType != null + && (systemTaskRegistry.isSystemTask(forkTaskType)) + && forkTaskName == null) { + forkTaskName = forkTaskType; + } + if (forkTaskName == null) { + forkTaskName = workflowTask.getTaskReferenceName(); + // or we can ban using just forkTaskWorkflow without forkTaskName + } + + if (forkTaskType == null) { + forkTaskType = TASK_TYPE_SIMPLE; + } + + // This should be a list + Object forkTaskInputs = input.get("forkTaskInputs"); + if (forkTaskInputs == null || !(forkTaskInputs instanceof List)) { + LOGGER.warn( + "fork_task_name is present but the inputs are NOT a list is empty {}", + forkTaskInputs); + return null; + } + List inputs = (List) forkTaskInputs; + + List dynamicForkWorkflowTasks = new ArrayList<>(inputs.size()); + Map> dynamicForkTasksInput = new HashMap<>(); + int i = 0; + for (Object forkTaskInput : inputs) { + WorkflowTask forkTask = null; + if (forkSubWorkflowName != null) { + forkTask = + generateSubWorkflowWorkflowTask( + forkSubWorkflowName, forkSubWorkflowVersion, forkTaskInput); + forkTask.setTaskReferenceName("_" + forkTaskName + "_" + i); + } else { + forkTask = generateWorkflowTask(forkTaskName, forkTaskType, forkTaskInput); + forkTask.setTaskReferenceName("_" + forkTaskName + "_" + i); + } + forkTask.getInputParameters().put("__index", i++); + if (workflowTask.isOptional()) { + forkTask.setOptional(true); + } + + dynamicForkWorkflowTasks.add(forkTask); + dynamicForkTasksInput.put( + forkTask.getTaskReferenceName(), forkTask.getInputParameters()); + } + return new ImmutablePair<>(dynamicForkWorkflowTasks, dynamicForkTasksInput); + } + + private WorkflowTask generateWorkflowTask( + String forkTaskName, String forkTaskType, Object forkTaskInput) { + WorkflowTask forkTask = new WorkflowTask(); + + try { + forkTask = objectMapper.convertValue(forkTaskInput, WorkflowTask.class); + } catch (Exception ignored) { + } + + forkTask.setName(forkTaskName); + forkTask.setType(forkTaskType); + Map inputParameters = new HashMap<>(); + + if (forkTaskInput instanceof Map) { + inputParameters.putAll((Map) forkTaskInput); + } else { + inputParameters.put("input", forkTaskInput); + } + forkTask.setInputParameters(inputParameters); + forkTask.setTaskDefinition(metadataDAO.getTaskDef(forkTaskName)); + return forkTask; + } + + private WorkflowTask generateSubWorkflowWorkflowTask( + String name, Integer version, Object forkTaskInput) { + WorkflowTask forkTask = new WorkflowTask(); + + try { + forkTask = objectMapper.convertValue(forkTaskInput, WorkflowTask.class); + } catch (Exception ignored) { + } + + forkTask.setName(name); + forkTask.setType(SUB_WORKFLOW.toString()); + Map inputParameters = new HashMap<>(); + SubWorkflowParams subWorkflowParams = new SubWorkflowParams(); + subWorkflowParams.setName(name); + subWorkflowParams.setVersion(version); + forkTask.setSubWorkflowParam(subWorkflowParams); + + if (forkTaskInput instanceof Map) { + inputParameters.putAll((Map) forkTaskInput); + Map forkTaskInputMap = (Map) forkTaskInput; + subWorkflowParams.setTaskToDomain( + (Map) forkTaskInputMap.get("taskToDomain")); + } else { + inputParameters.put("input", forkTaskInput); + } + forkTask.setInputParameters(inputParameters); + return forkTask; + } + /** * This method is used to get the List of dynamic workflow tasks and their input based on the * {@link WorkflowTask#getDynamicForkJoinTasksParam()} @@ -366,12 +541,9 @@ Pair, Map>> getDynamicForkTasksAn */ @VisibleForTesting Pair, Map>> getDynamicForkJoinTasksAndInput( - WorkflowTask workflowTask, WorkflowModel workflowModel) + WorkflowTask workflowTask, WorkflowModel workflowModel, Map input) throws TerminateWorkflowException { String dynamicForkJoinTaskParam = workflowTask.getDynamicForkJoinTasksParam(); - Map input = - parametersUtils.getTaskInput( - workflowTask.getInputParameters(), workflowModel, null, null); Object paramValue = input.get(dynamicForkJoinTaskParam); DynamicForkJoinTaskList dynamicForkJoinTaskList = objectMapper.convertValue(paramValue, DynamicForkJoinTaskList.class); diff --git a/core/src/main/java/com/netflix/conductor/core/execution/mapper/ForkJoinTaskMapper.java b/core/src/main/java/com/netflix/conductor/core/execution/mapper/ForkJoinTaskMapper.java index 7ac7f7d3d..aefabb0a1 100644 --- a/core/src/main/java/com/netflix/conductor/core/execution/mapper/ForkJoinTaskMapper.java +++ b/core/src/main/java/com/netflix/conductor/core/execution/mapper/ForkJoinTaskMapper.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/core/src/main/java/com/netflix/conductor/core/execution/mapper/HTTPTaskMapper.java b/core/src/main/java/com/netflix/conductor/core/execution/mapper/HTTPTaskMapper.java index 123e0aa76..4ac2bb4b8 100644 --- a/core/src/main/java/com/netflix/conductor/core/execution/mapper/HTTPTaskMapper.java +++ b/core/src/main/java/com/netflix/conductor/core/execution/mapper/HTTPTaskMapper.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at @@ -16,7 +16,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import com.netflix.conductor.common.metadata.tasks.TaskDef; @@ -42,7 +41,6 @@ public class HTTPTaskMapper implements TaskMapper { private final ParametersUtils parametersUtils; private final MetadataDAO metadataDAO; - @Autowired public HTTPTaskMapper(ParametersUtils parametersUtils, MetadataDAO metadataDAO) { this.parametersUtils = parametersUtils; this.metadataDAO = metadataDAO; diff --git a/core/src/main/java/com/netflix/conductor/core/execution/mapper/HumanTaskMapper.java b/core/src/main/java/com/netflix/conductor/core/execution/mapper/HumanTaskMapper.java index 781dac871..4484337f7 100644 --- a/core/src/main/java/com/netflix/conductor/core/execution/mapper/HumanTaskMapper.java +++ b/core/src/main/java/com/netflix/conductor/core/execution/mapper/HumanTaskMapper.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/core/src/main/java/com/netflix/conductor/core/execution/mapper/InlineTaskMapper.java b/core/src/main/java/com/netflix/conductor/core/execution/mapper/InlineTaskMapper.java index ac95c5d22..87eac7259 100644 --- a/core/src/main/java/com/netflix/conductor/core/execution/mapper/InlineTaskMapper.java +++ b/core/src/main/java/com/netflix/conductor/core/execution/mapper/InlineTaskMapper.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/core/src/main/java/com/netflix/conductor/core/execution/mapper/JoinTaskMapper.java b/core/src/main/java/com/netflix/conductor/core/execution/mapper/JoinTaskMapper.java index 9e78154c5..6ae3adb1e 100644 --- a/core/src/main/java/com/netflix/conductor/core/execution/mapper/JoinTaskMapper.java +++ b/core/src/main/java/com/netflix/conductor/core/execution/mapper/JoinTaskMapper.java @@ -1,5 +1,5 @@ /* - * Copyright 2021 Netflix, Inc. + * Copyright 2021 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/core/src/main/java/com/netflix/conductor/core/execution/mapper/JsonJQTransformTaskMapper.java b/core/src/main/java/com/netflix/conductor/core/execution/mapper/JsonJQTransformTaskMapper.java index c4f0eaeb0..21828e3b7 100644 --- a/core/src/main/java/com/netflix/conductor/core/execution/mapper/JsonJQTransformTaskMapper.java +++ b/core/src/main/java/com/netflix/conductor/core/execution/mapper/JsonJQTransformTaskMapper.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/core/src/main/java/com/netflix/conductor/core/execution/mapper/KafkaPublishTaskMapper.java b/core/src/main/java/com/netflix/conductor/core/execution/mapper/KafkaPublishTaskMapper.java index 280bf71d5..455e337f2 100644 --- a/core/src/main/java/com/netflix/conductor/core/execution/mapper/KafkaPublishTaskMapper.java +++ b/core/src/main/java/com/netflix/conductor/core/execution/mapper/KafkaPublishTaskMapper.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at @@ -20,7 +20,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import com.netflix.conductor.common.metadata.tasks.TaskDef; @@ -41,7 +40,6 @@ public class KafkaPublishTaskMapper implements TaskMapper { private final ParametersUtils parametersUtils; private final MetadataDAO metadataDAO; - @Autowired public KafkaPublishTaskMapper(ParametersUtils parametersUtils, MetadataDAO metadataDAO) { this.parametersUtils = parametersUtils; this.metadataDAO = metadataDAO; diff --git a/core/src/main/java/com/netflix/conductor/core/execution/mapper/LambdaTaskMapper.java b/core/src/main/java/com/netflix/conductor/core/execution/mapper/LambdaTaskMapper.java index 0f39ae363..37294faa2 100644 --- a/core/src/main/java/com/netflix/conductor/core/execution/mapper/LambdaTaskMapper.java +++ b/core/src/main/java/com/netflix/conductor/core/execution/mapper/LambdaTaskMapper.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/core/src/main/java/com/netflix/conductor/core/execution/mapper/NoopTaskMapper.java b/core/src/main/java/com/netflix/conductor/core/execution/mapper/NoopTaskMapper.java index a7f904582..17a53dba4 100644 --- a/core/src/main/java/com/netflix/conductor/core/execution/mapper/NoopTaskMapper.java +++ b/core/src/main/java/com/netflix/conductor/core/execution/mapper/NoopTaskMapper.java @@ -1,5 +1,5 @@ /* - * Copyright 2023 Netflix, Inc. + * Copyright 2023 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/core/src/main/java/com/netflix/conductor/core/execution/mapper/SetVariableTaskMapper.java b/core/src/main/java/com/netflix/conductor/core/execution/mapper/SetVariableTaskMapper.java index 7881fb87f..e12caf47e 100644 --- a/core/src/main/java/com/netflix/conductor/core/execution/mapper/SetVariableTaskMapper.java +++ b/core/src/main/java/com/netflix/conductor/core/execution/mapper/SetVariableTaskMapper.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/core/src/main/java/com/netflix/conductor/core/execution/mapper/SimpleTaskMapper.java b/core/src/main/java/com/netflix/conductor/core/execution/mapper/SimpleTaskMapper.java index 1dcf9ddb0..0e1368cd1 100644 --- a/core/src/main/java/com/netflix/conductor/core/execution/mapper/SimpleTaskMapper.java +++ b/core/src/main/java/com/netflix/conductor/core/execution/mapper/SimpleTaskMapper.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/core/src/main/java/com/netflix/conductor/core/execution/mapper/StartWorkflowTaskMapper.java b/core/src/main/java/com/netflix/conductor/core/execution/mapper/StartWorkflowTaskMapper.java index 4d965bc03..5a377750f 100644 --- a/core/src/main/java/com/netflix/conductor/core/execution/mapper/StartWorkflowTaskMapper.java +++ b/core/src/main/java/com/netflix/conductor/core/execution/mapper/StartWorkflowTaskMapper.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/core/src/main/java/com/netflix/conductor/core/execution/mapper/SubWorkflowTaskMapper.java b/core/src/main/java/com/netflix/conductor/core/execution/mapper/SubWorkflowTaskMapper.java index a90964dac..ab7d9c291 100644 --- a/core/src/main/java/com/netflix/conductor/core/execution/mapper/SubWorkflowTaskMapper.java +++ b/core/src/main/java/com/netflix/conductor/core/execution/mapper/SubWorkflowTaskMapper.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/core/src/main/java/com/netflix/conductor/core/execution/mapper/SwitchTaskMapper.java b/core/src/main/java/com/netflix/conductor/core/execution/mapper/SwitchTaskMapper.java index 3503dbb29..b59f861b7 100644 --- a/core/src/main/java/com/netflix/conductor/core/execution/mapper/SwitchTaskMapper.java +++ b/core/src/main/java/com/netflix/conductor/core/execution/mapper/SwitchTaskMapper.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at @@ -18,7 +18,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import com.netflix.conductor.common.metadata.tasks.TaskType; @@ -42,7 +41,6 @@ public class SwitchTaskMapper implements TaskMapper { private final Map evaluators; - @Autowired public SwitchTaskMapper(Map evaluators) { this.evaluators = evaluators; } diff --git a/core/src/main/java/com/netflix/conductor/core/execution/mapper/TaskMapper.java b/core/src/main/java/com/netflix/conductor/core/execution/mapper/TaskMapper.java index a80a9076e..9f7d83e4c 100644 --- a/core/src/main/java/com/netflix/conductor/core/execution/mapper/TaskMapper.java +++ b/core/src/main/java/com/netflix/conductor/core/execution/mapper/TaskMapper.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/core/src/main/java/com/netflix/conductor/core/execution/mapper/TaskMapperContext.java b/core/src/main/java/com/netflix/conductor/core/execution/mapper/TaskMapperContext.java index a34c4a0e4..44f996268 100644 --- a/core/src/main/java/com/netflix/conductor/core/execution/mapper/TaskMapperContext.java +++ b/core/src/main/java/com/netflix/conductor/core/execution/mapper/TaskMapperContext.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/core/src/main/java/com/netflix/conductor/core/execution/mapper/TerminateTaskMapper.java b/core/src/main/java/com/netflix/conductor/core/execution/mapper/TerminateTaskMapper.java index 0491df06d..886f20420 100644 --- a/core/src/main/java/com/netflix/conductor/core/execution/mapper/TerminateTaskMapper.java +++ b/core/src/main/java/com/netflix/conductor/core/execution/mapper/TerminateTaskMapper.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/core/src/main/java/com/netflix/conductor/core/execution/mapper/UserDefinedTaskMapper.java b/core/src/main/java/com/netflix/conductor/core/execution/mapper/UserDefinedTaskMapper.java index b98288577..ba8f314d2 100644 --- a/core/src/main/java/com/netflix/conductor/core/execution/mapper/UserDefinedTaskMapper.java +++ b/core/src/main/java/com/netflix/conductor/core/execution/mapper/UserDefinedTaskMapper.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/core/src/main/java/com/netflix/conductor/core/execution/mapper/WaitTaskMapper.java b/core/src/main/java/com/netflix/conductor/core/execution/mapper/WaitTaskMapper.java index 6a3ca95d1..fc58d892e 100644 --- a/core/src/main/java/com/netflix/conductor/core/execution/mapper/WaitTaskMapper.java +++ b/core/src/main/java/com/netflix/conductor/core/execution/mapper/WaitTaskMapper.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/core/src/main/java/com/netflix/conductor/core/execution/tasks/Decision.java b/core/src/main/java/com/netflix/conductor/core/execution/tasks/Decision.java index 0a96845f7..90941edf2 100644 --- a/core/src/main/java/com/netflix/conductor/core/execution/tasks/Decision.java +++ b/core/src/main/java/com/netflix/conductor/core/execution/tasks/Decision.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/core/src/main/java/com/netflix/conductor/core/execution/tasks/DoWhile.java b/core/src/main/java/com/netflix/conductor/core/execution/tasks/DoWhile.java index 3dbc72eb9..2e61b4fe7 100644 --- a/core/src/main/java/com/netflix/conductor/core/execution/tasks/DoWhile.java +++ b/core/src/main/java/com/netflix/conductor/core/execution/tasks/DoWhile.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at @@ -14,6 +14,7 @@ import java.util.*; import java.util.stream.Collectors; +import java.util.stream.IntStream; import javax.script.ScriptException; @@ -111,6 +112,17 @@ public boolean execute( } doWhileTaskModel.addOutput(String.valueOf(doWhileTaskModel.getIteration()), output); + Optional keepLastN = + Optional.ofNullable(doWhileTaskModel.getWorkflowTask().getInputParameters()) + .map(parameters -> parameters.get("keepLastN")) + .map(value -> (Integer) value); + if (keepLastN.isPresent() && doWhileTaskModel.getIteration() > keepLastN.get()) { + Integer iteration = doWhileTaskModel.getIteration(); + IntStream.range(0, iteration - keepLastN.get() - 1) + .mapToObj(Integer::toString) + .forEach(doWhileTaskModel::removeOutput); + } + if (hasFailures) { LOGGER.debug( "Task {} failed in {} iteration", diff --git a/core/src/main/java/com/netflix/conductor/core/execution/tasks/Event.java b/core/src/main/java/com/netflix/conductor/core/execution/tasks/Event.java index 8c543ca46..9674efe07 100644 --- a/core/src/main/java/com/netflix/conductor/core/execution/tasks/Event.java +++ b/core/src/main/java/com/netflix/conductor/core/execution/tasks/Event.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/core/src/main/java/com/netflix/conductor/core/execution/tasks/ExclusiveJoin.java b/core/src/main/java/com/netflix/conductor/core/execution/tasks/ExclusiveJoin.java index e2bf0ac0b..9800eb451 100644 --- a/core/src/main/java/com/netflix/conductor/core/execution/tasks/ExclusiveJoin.java +++ b/core/src/main/java/com/netflix/conductor/core/execution/tasks/ExclusiveJoin.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at @@ -65,9 +65,20 @@ public boolean execute( } taskStatus = exclusiveTask.getStatus(); foundExlusiveJoinOnTask = taskStatus.isTerminal(); - hasFailures = !taskStatus.isSuccessful(); + hasFailures = + !taskStatus.isSuccessful() + && (!exclusiveTask.getWorkflowTask().isPermissive() + || joinOn.stream() + .map(workflow::getTaskByRefName) + .allMatch(t -> t.getStatus().isTerminal())); if (hasFailures) { - failureReason.append(exclusiveTask.getReasonForIncompletion()).append(" "); + final String failureReasons = + joinOn.stream() + .map(workflow::getTaskByRefName) + .filter(t -> !t.getStatus().isSuccessful()) + .map(TaskModel::getReasonForIncompletion) + .collect(Collectors.joining(" ")); + failureReason.append(failureReasons); } break; diff --git a/core/src/main/java/com/netflix/conductor/core/execution/tasks/ExecutionConfig.java b/core/src/main/java/com/netflix/conductor/core/execution/tasks/ExecutionConfig.java index 7115dfd1d..0f1a996e7 100644 --- a/core/src/main/java/com/netflix/conductor/core/execution/tasks/ExecutionConfig.java +++ b/core/src/main/java/com/netflix/conductor/core/execution/tasks/ExecutionConfig.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/core/src/main/java/com/netflix/conductor/core/execution/tasks/Fork.java b/core/src/main/java/com/netflix/conductor/core/execution/tasks/Fork.java index 9f31af750..6d7ddf74f 100644 --- a/core/src/main/java/com/netflix/conductor/core/execution/tasks/Fork.java +++ b/core/src/main/java/com/netflix/conductor/core/execution/tasks/Fork.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/core/src/main/java/com/netflix/conductor/core/execution/tasks/Human.java b/core/src/main/java/com/netflix/conductor/core/execution/tasks/Human.java index c4dfc4e31..15528652c 100644 --- a/core/src/main/java/com/netflix/conductor/core/execution/tasks/Human.java +++ b/core/src/main/java/com/netflix/conductor/core/execution/tasks/Human.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/core/src/main/java/com/netflix/conductor/core/execution/tasks/Inline.java b/core/src/main/java/com/netflix/conductor/core/execution/tasks/Inline.java index e53bd7dd4..5641fb441 100644 --- a/core/src/main/java/com/netflix/conductor/core/execution/tasks/Inline.java +++ b/core/src/main/java/com/netflix/conductor/core/execution/tasks/Inline.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/core/src/main/java/com/netflix/conductor/core/execution/tasks/IsolatedTaskQueueProducer.java b/core/src/main/java/com/netflix/conductor/core/execution/tasks/IsolatedTaskQueueProducer.java index 5a5ac33a8..9ac9b4bab 100644 --- a/core/src/main/java/com/netflix/conductor/core/execution/tasks/IsolatedTaskQueueProducer.java +++ b/core/src/main/java/com/netflix/conductor/core/execution/tasks/IsolatedTaskQueueProducer.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/core/src/main/java/com/netflix/conductor/core/execution/tasks/Join.java b/core/src/main/java/com/netflix/conductor/core/execution/tasks/Join.java index e0f7be9fa..5b0db258b 100644 --- a/core/src/main/java/com/netflix/conductor/core/execution/tasks/Join.java +++ b/core/src/main/java/com/netflix/conductor/core/execution/tasks/Join.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at @@ -13,6 +13,7 @@ package com.netflix.conductor.core.execution.tasks; import java.util.List; +import java.util.Objects; import java.util.Optional; import java.util.stream.Collectors; @@ -36,9 +37,6 @@ public Join() { @SuppressWarnings("unchecked") public boolean execute( WorkflowModel workflow, TaskModel task, WorkflowExecutor workflowExecutor) { - - boolean allDone = true; - boolean hasFailures = false; StringBuilder failureReason = new StringBuilder(); StringBuilder optionalTaskFailures = new StringBuilder(); List joinOn = (List) task.getInputData().get("joinOn"); @@ -47,29 +45,47 @@ public boolean execute( joinOn = joinOn.stream() .map(name -> TaskUtils.appendIteration(name, task.getIteration())) - .collect(Collectors.toList()); + .toList(); } + + boolean allTasksTerminal = + joinOn.stream() + .map(workflow::getTaskByRefName) + .allMatch(t -> t != null && t.getStatus().isTerminal()); + for (String joinOnRef : joinOn) { TaskModel forkedTask = workflow.getTaskByRefName(joinOnRef); if (forkedTask == null) { - // Task is not even scheduled yet - allDone = false; - break; + // Continue checking other tasks if a referenced task is not yet scheduled + continue; } + TaskModel.Status taskStatus = forkedTask.getStatus(); - hasFailures = !taskStatus.isSuccessful() && !forkedTask.getWorkflowTask().isOptional(); - if (hasFailures) { - failureReason.append(forkedTask.getReasonForIncompletion()).append(" "); - } + // Only add to task output if it's not empty if (!forkedTask.getOutputData().isEmpty()) { task.addOutput(joinOnRef, forkedTask.getOutputData()); } - if (!taskStatus.isTerminal()) { - allDone = false; - } - if (hasFailures) { - break; + + // Determine if the join task fails immediately due to a non-optional, non-permissive + // task failure, + // or waits for all tasks to be terminal if the failed task is permissive. + var isJoinFailure = + !taskStatus.isSuccessful() + && !forkedTask.getWorkflowTask().isOptional() + && (!forkedTask.getWorkflowTask().isPermissive() || allTasksTerminal); + if (isJoinFailure) { + final String failureReasons = + joinOn.stream() + .map(workflow::getTaskByRefName) + .filter(Objects::nonNull) + .filter(t -> !t.getStatus().isSuccessful()) + .map(TaskModel::getReasonForIncompletion) + .collect(Collectors.joining(" ")); + failureReason.append(failureReasons); + task.setReasonForIncompletion(failureReason.toString()); + task.setStatus(TaskModel.Status.FAILED); + return true; } // check for optional task failures @@ -83,11 +99,10 @@ public boolean execute( .append(" "); } } - if (allDone || hasFailures || optionalTaskFailures.length() > 0) { - if (hasFailures) { - task.setReasonForIncompletion(failureReason.toString()); - task.setStatus(TaskModel.Status.FAILED); - } else if (optionalTaskFailures.length() > 0) { + + // Finalize the join task's status based on the outcomes of all referenced tasks. + if (allTasksTerminal) { + if (!optionalTaskFailures.isEmpty()) { task.setStatus(TaskModel.Status.COMPLETED_WITH_ERRORS); optionalTaskFailures.append("completed with errors"); task.setReasonForIncompletion(optionalTaskFailures.toString()); @@ -96,6 +111,8 @@ public boolean execute( } return true; } + + // Task execution not complete, waiting on more tasks to reach terminal state. return false; } diff --git a/core/src/main/java/com/netflix/conductor/core/execution/tasks/Lambda.java b/core/src/main/java/com/netflix/conductor/core/execution/tasks/Lambda.java index d75360e2b..8df79263e 100644 --- a/core/src/main/java/com/netflix/conductor/core/execution/tasks/Lambda.java +++ b/core/src/main/java/com/netflix/conductor/core/execution/tasks/Lambda.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/core/src/main/java/com/netflix/conductor/core/execution/tasks/Noop.java b/core/src/main/java/com/netflix/conductor/core/execution/tasks/Noop.java index 4b9de40a2..49e6083cd 100644 --- a/core/src/main/java/com/netflix/conductor/core/execution/tasks/Noop.java +++ b/core/src/main/java/com/netflix/conductor/core/execution/tasks/Noop.java @@ -1,5 +1,5 @@ /* - * Copyright 2023 Netflix, Inc. + * Copyright 2023 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/core/src/main/java/com/netflix/conductor/core/execution/tasks/SetVariable.java b/core/src/main/java/com/netflix/conductor/core/execution/tasks/SetVariable.java index 8353e6a2e..0c8327958 100644 --- a/core/src/main/java/com/netflix/conductor/core/execution/tasks/SetVariable.java +++ b/core/src/main/java/com/netflix/conductor/core/execution/tasks/SetVariable.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at @@ -66,7 +66,7 @@ private boolean validateVariablesSize( if (payloadSize > maxThreshold * 1024) { String errorMsg = String.format( - "The variables payload size: %d of workflow: %s is greater than the permissible limit: %d bytes", + "The variables payload size: %d of workflow: %s is greater than the permissible limit: %d kilobytes", payloadSize, workflowId, maxThreshold); LOGGER.error(errorMsg); task.setReasonForIncompletion(errorMsg); diff --git a/core/src/main/java/com/netflix/conductor/core/execution/tasks/StartWorkflow.java b/core/src/main/java/com/netflix/conductor/core/execution/tasks/StartWorkflow.java index 76edb8a68..b9cb01e0c 100644 --- a/core/src/main/java/com/netflix/conductor/core/execution/tasks/StartWorkflow.java +++ b/core/src/main/java/com/netflix/conductor/core/execution/tasks/StartWorkflow.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at @@ -15,8 +15,6 @@ import java.util.HashMap; import java.util.Map; -import javax.validation.Validator; - import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -31,6 +29,7 @@ import com.netflix.conductor.model.WorkflowModel; import com.fasterxml.jackson.databind.ObjectMapper; +import jakarta.validation.Validator; import static com.netflix.conductor.common.metadata.tasks.TaskType.TASK_TYPE_START_WORKFLOW; import static com.netflix.conductor.model.TaskModel.Status.COMPLETED; diff --git a/core/src/main/java/com/netflix/conductor/core/execution/tasks/SubWorkflow.java b/core/src/main/java/com/netflix/conductor/core/execution/tasks/SubWorkflow.java index 4b0cc6f04..3c9dcb769 100644 --- a/core/src/main/java/com/netflix/conductor/core/execution/tasks/SubWorkflow.java +++ b/core/src/main/java/com/netflix/conductor/core/execution/tasks/SubWorkflow.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at @@ -147,11 +147,6 @@ public void cancel(WorkflowModel workflow, TaskModel task, WorkflowExecutor work workflowExecutor.terminateWorkflow(subWorkflow, reason, null); } - @Override - public boolean isAsync() { - return true; - } - /** * Keep Subworkflow task asyncComplete. The Subworkflow task will be executed once * asynchronously to move to IN_PROGRESS state, and will move to termination by Subworkflow's diff --git a/core/src/main/java/com/netflix/conductor/core/execution/tasks/Switch.java b/core/src/main/java/com/netflix/conductor/core/execution/tasks/Switch.java index 2d3d040a2..bcbd00417 100644 --- a/core/src/main/java/com/netflix/conductor/core/execution/tasks/Switch.java +++ b/core/src/main/java/com/netflix/conductor/core/execution/tasks/Switch.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/core/src/main/java/com/netflix/conductor/core/execution/tasks/SystemTaskRegistry.java b/core/src/main/java/com/netflix/conductor/core/execution/tasks/SystemTaskRegistry.java index 4486680e8..7b9cf743b 100644 --- a/core/src/main/java/com/netflix/conductor/core/execution/tasks/SystemTaskRegistry.java +++ b/core/src/main/java/com/netflix/conductor/core/execution/tasks/SystemTaskRegistry.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/core/src/main/java/com/netflix/conductor/core/execution/tasks/SystemTaskWorker.java b/core/src/main/java/com/netflix/conductor/core/execution/tasks/SystemTaskWorker.java index 9b573f4af..d13334708 100644 --- a/core/src/main/java/com/netflix/conductor/core/execution/tasks/SystemTaskWorker.java +++ b/core/src/main/java/com/netflix/conductor/core/execution/tasks/SystemTaskWorker.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/core/src/main/java/com/netflix/conductor/core/execution/tasks/SystemTaskWorkerCoordinator.java b/core/src/main/java/com/netflix/conductor/core/execution/tasks/SystemTaskWorkerCoordinator.java index b1a9ed988..c192a9639 100644 --- a/core/src/main/java/com/netflix/conductor/core/execution/tasks/SystemTaskWorkerCoordinator.java +++ b/core/src/main/java/com/netflix/conductor/core/execution/tasks/SystemTaskWorkerCoordinator.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/core/src/main/java/com/netflix/conductor/core/execution/tasks/Terminate.java b/core/src/main/java/com/netflix/conductor/core/execution/tasks/Terminate.java index 230ab82c2..23eed4196 100644 --- a/core/src/main/java/com/netflix/conductor/core/execution/tasks/Terminate.java +++ b/core/src/main/java/com/netflix/conductor/core/execution/tasks/Terminate.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/core/src/main/java/com/netflix/conductor/core/execution/tasks/Wait.java b/core/src/main/java/com/netflix/conductor/core/execution/tasks/Wait.java index 903355aa6..2e1a1cc2f 100644 --- a/core/src/main/java/com/netflix/conductor/core/execution/tasks/Wait.java +++ b/core/src/main/java/com/netflix/conductor/core/execution/tasks/Wait.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/core/src/main/java/com/netflix/conductor/core/execution/tasks/WorkflowSystemTask.java b/core/src/main/java/com/netflix/conductor/core/execution/tasks/WorkflowSystemTask.java index b531d0001..9cc17b9e4 100644 --- a/core/src/main/java/com/netflix/conductor/core/execution/tasks/WorkflowSystemTask.java +++ b/core/src/main/java/com/netflix/conductor/core/execution/tasks/WorkflowSystemTask.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/core/src/main/java/com/netflix/conductor/core/index/NoopIndexDAO.java b/core/src/main/java/com/netflix/conductor/core/index/NoopIndexDAO.java index 5b2d95870..2472c4b38 100644 --- a/core/src/main/java/com/netflix/conductor/core/index/NoopIndexDAO.java +++ b/core/src/main/java/com/netflix/conductor/core/index/NoopIndexDAO.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/core/src/main/java/com/netflix/conductor/core/index/NoopIndexDAOConfiguration.java b/core/src/main/java/com/netflix/conductor/core/index/NoopIndexDAOConfiguration.java index 0e9e2466b..5de6a6e51 100644 --- a/core/src/main/java/com/netflix/conductor/core/index/NoopIndexDAOConfiguration.java +++ b/core/src/main/java/com/netflix/conductor/core/index/NoopIndexDAOConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/core/src/main/java/com/netflix/conductor/core/listener/TaskStatusListener.java b/core/src/main/java/com/netflix/conductor/core/listener/TaskStatusListener.java index 2fea7d065..0fc6d61d4 100644 --- a/core/src/main/java/com/netflix/conductor/core/listener/TaskStatusListener.java +++ b/core/src/main/java/com/netflix/conductor/core/listener/TaskStatusListener.java @@ -1,5 +1,5 @@ /* - * Copyright 2023 Netflix, Inc. + * Copyright 2023 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/core/src/main/java/com/netflix/conductor/core/listener/TaskStatusListenerStub.java b/core/src/main/java/com/netflix/conductor/core/listener/TaskStatusListenerStub.java index 413f5a69e..a53d05243 100644 --- a/core/src/main/java/com/netflix/conductor/core/listener/TaskStatusListenerStub.java +++ b/core/src/main/java/com/netflix/conductor/core/listener/TaskStatusListenerStub.java @@ -1,5 +1,5 @@ /* - * Copyright 2023 Netflix, Inc. + * Copyright 2023 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/core/src/main/java/com/netflix/conductor/core/listener/WorkflowStatusListener.java b/core/src/main/java/com/netflix/conductor/core/listener/WorkflowStatusListener.java index 1c0c4395a..18dbfeb29 100644 --- a/core/src/main/java/com/netflix/conductor/core/listener/WorkflowStatusListener.java +++ b/core/src/main/java/com/netflix/conductor/core/listener/WorkflowStatusListener.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/core/src/main/java/com/netflix/conductor/core/listener/WorkflowStatusListenerStub.java b/core/src/main/java/com/netflix/conductor/core/listener/WorkflowStatusListenerStub.java index 36bb5e699..63fe09070 100644 --- a/core/src/main/java/com/netflix/conductor/core/listener/WorkflowStatusListenerStub.java +++ b/core/src/main/java/com/netflix/conductor/core/listener/WorkflowStatusListenerStub.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/core/src/main/java/com/netflix/conductor/core/metadata/MetadataMapperService.java b/core/src/main/java/com/netflix/conductor/core/metadata/MetadataMapperService.java index 7a825adac..31e4abaca 100644 --- a/core/src/main/java/com/netflix/conductor/core/metadata/MetadataMapperService.java +++ b/core/src/main/java/com/netflix/conductor/core/metadata/MetadataMapperService.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/core/src/main/java/com/netflix/conductor/core/operation/StartWorkflowOperation.java b/core/src/main/java/com/netflix/conductor/core/operation/StartWorkflowOperation.java index e9281de64..3ac92eb53 100644 --- a/core/src/main/java/com/netflix/conductor/core/operation/StartWorkflowOperation.java +++ b/core/src/main/java/com/netflix/conductor/core/operation/StartWorkflowOperation.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/core/src/main/java/com/netflix/conductor/core/operation/WorkflowOperation.java b/core/src/main/java/com/netflix/conductor/core/operation/WorkflowOperation.java index c0b428cf9..73a000042 100644 --- a/core/src/main/java/com/netflix/conductor/core/operation/WorkflowOperation.java +++ b/core/src/main/java/com/netflix/conductor/core/operation/WorkflowOperation.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/core/src/main/java/com/netflix/conductor/core/reconciliation/WorkflowReconciler.java b/core/src/main/java/com/netflix/conductor/core/reconciliation/WorkflowReconciler.java index d5e8fe5db..a95d1920f 100644 --- a/core/src/main/java/com/netflix/conductor/core/reconciliation/WorkflowReconciler.java +++ b/core/src/main/java/com/netflix/conductor/core/reconciliation/WorkflowReconciler.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/core/src/main/java/com/netflix/conductor/core/reconciliation/WorkflowRepairService.java b/core/src/main/java/com/netflix/conductor/core/reconciliation/WorkflowRepairService.java index 49ca8a632..2266f604f 100644 --- a/core/src/main/java/com/netflix/conductor/core/reconciliation/WorkflowRepairService.java +++ b/core/src/main/java/com/netflix/conductor/core/reconciliation/WorkflowRepairService.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/core/src/main/java/com/netflix/conductor/core/reconciliation/WorkflowSweeper.java b/core/src/main/java/com/netflix/conductor/core/reconciliation/WorkflowSweeper.java index cd4b46be7..b12529a62 100644 --- a/core/src/main/java/com/netflix/conductor/core/reconciliation/WorkflowSweeper.java +++ b/core/src/main/java/com/netflix/conductor/core/reconciliation/WorkflowSweeper.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at @@ -19,7 +19,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Component; @@ -53,7 +52,6 @@ public class WorkflowSweeper { private static final String CLASS_NAME = WorkflowSweeper.class.getSimpleName(); - @Autowired public WorkflowSweeper( WorkflowExecutor workflowExecutor, Optional workflowRepairService, diff --git a/core/src/main/java/com/netflix/conductor/core/storage/DummyPayloadStorage.java b/core/src/main/java/com/netflix/conductor/core/storage/DummyPayloadStorage.java index a04a43710..a083405eb 100644 --- a/core/src/main/java/com/netflix/conductor/core/storage/DummyPayloadStorage.java +++ b/core/src/main/java/com/netflix/conductor/core/storage/DummyPayloadStorage.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/core/src/main/java/com/netflix/conductor/core/sync/Lock.java b/core/src/main/java/com/netflix/conductor/core/sync/Lock.java index cb8d5ccd4..b219d41f2 100644 --- a/core/src/main/java/com/netflix/conductor/core/sync/Lock.java +++ b/core/src/main/java/com/netflix/conductor/core/sync/Lock.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/core/src/main/java/com/netflix/conductor/core/sync/local/LocalOnlyLock.java b/core/src/main/java/com/netflix/conductor/core/sync/local/LocalOnlyLock.java index 17cbee4fe..97408257b 100644 --- a/core/src/main/java/com/netflix/conductor/core/sync/local/LocalOnlyLock.java +++ b/core/src/main/java/com/netflix/conductor/core/sync/local/LocalOnlyLock.java @@ -1,5 +1,5 @@ /* - * Copyright 2020 Netflix, Inc. + * Copyright 2020 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/core/src/main/java/com/netflix/conductor/core/sync/local/LocalOnlyLockConfiguration.java b/core/src/main/java/com/netflix/conductor/core/sync/local/LocalOnlyLockConfiguration.java index 41a025406..790fda65e 100644 --- a/core/src/main/java/com/netflix/conductor/core/sync/local/LocalOnlyLockConfiguration.java +++ b/core/src/main/java/com/netflix/conductor/core/sync/local/LocalOnlyLockConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2020 Netflix, Inc. + * Copyright 2020 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/core/src/main/java/com/netflix/conductor/core/sync/noop/NoopLock.java b/core/src/main/java/com/netflix/conductor/core/sync/noop/NoopLock.java index 5d492da1e..e372b26f7 100644 --- a/core/src/main/java/com/netflix/conductor/core/sync/noop/NoopLock.java +++ b/core/src/main/java/com/netflix/conductor/core/sync/noop/NoopLock.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/core/src/main/java/com/netflix/conductor/core/utils/DateTimeUtils.java b/core/src/main/java/com/netflix/conductor/core/utils/DateTimeUtils.java index ec7ce83f0..7da8e43e8 100644 --- a/core/src/main/java/com/netflix/conductor/core/utils/DateTimeUtils.java +++ b/core/src/main/java/com/netflix/conductor/core/utils/DateTimeUtils.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/core/src/main/java/com/netflix/conductor/core/utils/ExternalPayloadStorageUtils.java b/core/src/main/java/com/netflix/conductor/core/utils/ExternalPayloadStorageUtils.java index 7cbc80e9e..e9ff71f1a 100644 --- a/core/src/main/java/com/netflix/conductor/core/utils/ExternalPayloadStorageUtils.java +++ b/core/src/main/java/com/netflix/conductor/core/utils/ExternalPayloadStorageUtils.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/core/src/main/java/com/netflix/conductor/core/utils/IDGenerator.java b/core/src/main/java/com/netflix/conductor/core/utils/IDGenerator.java index 813d63aa9..0f9060416 100644 --- a/core/src/main/java/com/netflix/conductor/core/utils/IDGenerator.java +++ b/core/src/main/java/com/netflix/conductor/core/utils/IDGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/core/src/main/java/com/netflix/conductor/core/utils/JsonUtils.java b/core/src/main/java/com/netflix/conductor/core/utils/JsonUtils.java index 38f70218c..2ec74e5a3 100644 --- a/core/src/main/java/com/netflix/conductor/core/utils/JsonUtils.java +++ b/core/src/main/java/com/netflix/conductor/core/utils/JsonUtils.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/core/src/main/java/com/netflix/conductor/core/utils/ParametersUtils.java b/core/src/main/java/com/netflix/conductor/core/utils/ParametersUtils.java index 15f8363f6..199dbac47 100644 --- a/core/src/main/java/com/netflix/conductor/core/utils/ParametersUtils.java +++ b/core/src/main/java/com/netflix/conductor/core/utils/ParametersUtils.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/core/src/main/java/com/netflix/conductor/core/utils/QueueUtils.java b/core/src/main/java/com/netflix/conductor/core/utils/QueueUtils.java index bca477390..0fa463d93 100644 --- a/core/src/main/java/com/netflix/conductor/core/utils/QueueUtils.java +++ b/core/src/main/java/com/netflix/conductor/core/utils/QueueUtils.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/core/src/main/java/com/netflix/conductor/core/utils/SemaphoreUtil.java b/core/src/main/java/com/netflix/conductor/core/utils/SemaphoreUtil.java index 793494bd9..df4d23120 100644 --- a/core/src/main/java/com/netflix/conductor/core/utils/SemaphoreUtil.java +++ b/core/src/main/java/com/netflix/conductor/core/utils/SemaphoreUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/core/src/main/java/com/netflix/conductor/core/utils/Utils.java b/core/src/main/java/com/netflix/conductor/core/utils/Utils.java index e81b3cf58..2464d996b 100644 --- a/core/src/main/java/com/netflix/conductor/core/utils/Utils.java +++ b/core/src/main/java/com/netflix/conductor/core/utils/Utils.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/core/src/main/java/com/netflix/conductor/dao/ConcurrentExecutionLimitDAO.java b/core/src/main/java/com/netflix/conductor/dao/ConcurrentExecutionLimitDAO.java index 853a72e63..5ca70c6b0 100644 --- a/core/src/main/java/com/netflix/conductor/dao/ConcurrentExecutionLimitDAO.java +++ b/core/src/main/java/com/netflix/conductor/dao/ConcurrentExecutionLimitDAO.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/core/src/main/java/com/netflix/conductor/dao/EventHandlerDAO.java b/core/src/main/java/com/netflix/conductor/dao/EventHandlerDAO.java index 6c9dc47a9..5d4812190 100644 --- a/core/src/main/java/com/netflix/conductor/dao/EventHandlerDAO.java +++ b/core/src/main/java/com/netflix/conductor/dao/EventHandlerDAO.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/core/src/main/java/com/netflix/conductor/dao/ExecutionDAO.java b/core/src/main/java/com/netflix/conductor/dao/ExecutionDAO.java index 8e33cac29..b94ffaf59 100644 --- a/core/src/main/java/com/netflix/conductor/dao/ExecutionDAO.java +++ b/core/src/main/java/com/netflix/conductor/dao/ExecutionDAO.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/core/src/main/java/com/netflix/conductor/dao/IndexDAO.java b/core/src/main/java/com/netflix/conductor/dao/IndexDAO.java index 14e53b2ab..ed3ada875 100644 --- a/core/src/main/java/com/netflix/conductor/dao/IndexDAO.java +++ b/core/src/main/java/com/netflix/conductor/dao/IndexDAO.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/core/src/main/java/com/netflix/conductor/dao/MetadataDAO.java b/core/src/main/java/com/netflix/conductor/dao/MetadataDAO.java index b7e39cf3a..712096cd3 100644 --- a/core/src/main/java/com/netflix/conductor/dao/MetadataDAO.java +++ b/core/src/main/java/com/netflix/conductor/dao/MetadataDAO.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/core/src/main/java/com/netflix/conductor/dao/PollDataDAO.java b/core/src/main/java/com/netflix/conductor/dao/PollDataDAO.java index d53d6660d..7a1230d6c 100644 --- a/core/src/main/java/com/netflix/conductor/dao/PollDataDAO.java +++ b/core/src/main/java/com/netflix/conductor/dao/PollDataDAO.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/core/src/main/java/com/netflix/conductor/dao/QueueDAO.java b/core/src/main/java/com/netflix/conductor/dao/QueueDAO.java index 70b5857c5..eccfe07b0 100644 --- a/core/src/main/java/com/netflix/conductor/dao/QueueDAO.java +++ b/core/src/main/java/com/netflix/conductor/dao/QueueDAO.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/core/src/main/java/com/netflix/conductor/dao/RateLimitingDAO.java b/core/src/main/java/com/netflix/conductor/dao/RateLimitingDAO.java index 6ef4b4859..65ad25fa0 100644 --- a/core/src/main/java/com/netflix/conductor/dao/RateLimitingDAO.java +++ b/core/src/main/java/com/netflix/conductor/dao/RateLimitingDAO.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/core/src/main/java/com/netflix/conductor/metrics/Monitors.java b/core/src/main/java/com/netflix/conductor/metrics/Monitors.java index 862d3076d..cbe529ae4 100644 --- a/core/src/main/java/com/netflix/conductor/metrics/Monitors.java +++ b/core/src/main/java/com/netflix/conductor/metrics/Monitors.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/core/src/main/java/com/netflix/conductor/metrics/WorkflowMonitor.java b/core/src/main/java/com/netflix/conductor/metrics/WorkflowMonitor.java index 2f974ed68..e1e8fc637 100644 --- a/core/src/main/java/com/netflix/conductor/metrics/WorkflowMonitor.java +++ b/core/src/main/java/com/netflix/conductor/metrics/WorkflowMonitor.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/core/src/main/java/com/netflix/conductor/model/TaskModel.java b/core/src/main/java/com/netflix/conductor/model/TaskModel.java index 617b013da..122c31b5b 100644 --- a/core/src/main/java/com/netflix/conductor/model/TaskModel.java +++ b/core/src/main/java/com/netflix/conductor/model/TaskModel.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at @@ -571,6 +571,7 @@ public void incrementPollCount() { /** * @return {@link Optional} containing the task definition if available */ + @JsonIgnore public Optional getTaskDefinition() { return Optional.ofNullable(this.getWorkflowTask()).map(WorkflowTask::getTaskDefinition); } @@ -873,6 +874,10 @@ public void addOutput(String key, Object value) { this.outputData.put(key, value); } + public void removeOutput(String key) { + this.outputData.remove(key); + } + public void addOutput(Map outputData) { if (outputData != null) { this.outputData.putAll(outputData); diff --git a/core/src/main/java/com/netflix/conductor/model/WorkflowModel.java b/core/src/main/java/com/netflix/conductor/model/WorkflowModel.java index ca505aa9c..c0bfffccd 100644 --- a/core/src/main/java/com/netflix/conductor/model/WorkflowModel.java +++ b/core/src/main/java/com/netflix/conductor/model/WorkflowModel.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/core/src/main/java/com/netflix/conductor/service/AdminService.java b/core/src/main/java/com/netflix/conductor/service/AdminService.java index 84d68c279..973a3edc8 100644 --- a/core/src/main/java/com/netflix/conductor/service/AdminService.java +++ b/core/src/main/java/com/netflix/conductor/service/AdminService.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at @@ -15,12 +15,12 @@ import java.util.List; import java.util.Map; -import javax.validation.constraints.NotEmpty; - import org.springframework.validation.annotation.Validated; import com.netflix.conductor.common.metadata.tasks.Task; +import jakarta.validation.constraints.NotEmpty; + @Validated public interface AdminService { diff --git a/core/src/main/java/com/netflix/conductor/service/AdminServiceImpl.java b/core/src/main/java/com/netflix/conductor/service/AdminServiceImpl.java index bf470d4e8..8c11dd94b 100644 --- a/core/src/main/java/com/netflix/conductor/service/AdminServiceImpl.java +++ b/core/src/main/java/com/netflix/conductor/service/AdminServiceImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/core/src/main/java/com/netflix/conductor/service/EventService.java b/core/src/main/java/com/netflix/conductor/service/EventService.java index c2f29e734..3d42a872b 100644 --- a/core/src/main/java/com/netflix/conductor/service/EventService.java +++ b/core/src/main/java/com/netflix/conductor/service/EventService.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at @@ -14,14 +14,14 @@ import java.util.List; -import javax.validation.Valid; -import javax.validation.constraints.NotEmpty; -import javax.validation.constraints.NotNull; - import org.springframework.validation.annotation.Validated; import com.netflix.conductor.common.metadata.events.EventHandler; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; + @Validated public interface EventService { diff --git a/core/src/main/java/com/netflix/conductor/service/EventServiceImpl.java b/core/src/main/java/com/netflix/conductor/service/EventServiceImpl.java index b4b20bdf3..579986e11 100644 --- a/core/src/main/java/com/netflix/conductor/service/EventServiceImpl.java +++ b/core/src/main/java/com/netflix/conductor/service/EventServiceImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/core/src/main/java/com/netflix/conductor/service/ExecutionLockService.java b/core/src/main/java/com/netflix/conductor/service/ExecutionLockService.java index c45bba263..d9dbf6b7b 100644 --- a/core/src/main/java/com/netflix/conductor/service/ExecutionLockService.java +++ b/core/src/main/java/com/netflix/conductor/service/ExecutionLockService.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at @@ -16,7 +16,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.netflix.conductor.annotations.Trace; @@ -34,7 +33,6 @@ public class ExecutionLockService { private final long lockLeaseTime; private final long lockTimeToTry; - @Autowired public ExecutionLockService(ConductorProperties properties, Lock lock) { this.properties = properties; this.lock = lock; diff --git a/core/src/main/java/com/netflix/conductor/service/ExecutionService.java b/core/src/main/java/com/netflix/conductor/service/ExecutionService.java index a4e411b4e..2c985dec0 100644 --- a/core/src/main/java/com/netflix/conductor/service/ExecutionService.java +++ b/core/src/main/java/com/netflix/conductor/service/ExecutionService.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at @@ -14,6 +14,7 @@ import java.util.*; import java.util.stream.Collectors; +import java.util.stream.Stream; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; @@ -27,12 +28,14 @@ import com.netflix.conductor.common.utils.ExternalPayloadStorage; import com.netflix.conductor.common.utils.ExternalPayloadStorage.Operation; import com.netflix.conductor.common.utils.ExternalPayloadStorage.PayloadType; +import com.netflix.conductor.common.utils.TaskUtils; import com.netflix.conductor.core.config.ConductorProperties; import com.netflix.conductor.core.dal.ExecutionDAOFacade; import com.netflix.conductor.core.events.queue.Message; import com.netflix.conductor.core.exception.NotFoundException; import com.netflix.conductor.core.execution.WorkflowExecutor; import com.netflix.conductor.core.execution.tasks.SystemTaskRegistry; +import com.netflix.conductor.core.listener.TaskStatusListener; import com.netflix.conductor.core.utils.QueueUtils; import com.netflix.conductor.core.utils.Utils; import com.netflix.conductor.dao.QueueDAO; @@ -50,6 +53,7 @@ public class ExecutionService { private final QueueDAO queueDAO; private final ExternalPayloadStorage externalPayloadStorage; private final SystemTaskRegistry systemTaskRegistry; + private final TaskStatusListener taskStatusListener; private final long queueTaskMessagePostponeSecs; @@ -63,7 +67,8 @@ public ExecutionService( QueueDAO queueDAO, ConductorProperties properties, ExternalPayloadStorage externalPayloadStorage, - SystemTaskRegistry systemTaskRegistry) { + SystemTaskRegistry systemTaskRegistry, + TaskStatusListener taskStatusListener) { this.workflowExecutor = workflowExecutor; this.executionDAOFacade = executionDAOFacade; this.queueDAO = queueDAO; @@ -72,6 +77,7 @@ public ExecutionService( this.queueTaskMessagePostponeSecs = properties.getTaskExecutionPostponeDuration().getSeconds(); this.systemTaskRegistry = systemTaskRegistry; + this.taskStatusListener = taskStatusListener; } public Task poll(String taskType, String workerId) { @@ -179,6 +185,11 @@ public List poll( queueDAO.postpone(queueName, taskId, 0, queueTaskMessagePostponeSecs); } } + taskIds.stream() + .map(executionDAOFacade::getTaskModel) + .filter(Objects::nonNull) + .filter(task -> TaskModel.Status.IN_PROGRESS.equals(task.getStatus())) + .forEach(taskStatusListener::onTaskInProgress); executionDAOFacade.updateTaskLastPoll(taskType, domain, workerId); Monitors.recordTaskPoll(queueName); tasks.forEach(this::ackTaskReceived); @@ -252,12 +263,28 @@ public Task getTask(String taskId) { } public Task getPendingTaskForWorkflow(String taskReferenceName, String workflowId) { - return executionDAOFacade.getTasksForWorkflow(workflowId).stream() - .filter(task -> !task.getStatus().isTerminal()) - .filter(task -> task.getReferenceTaskName().equals(taskReferenceName)) - .findFirst() // There can only be one task by a given reference name running at a - // time. - .orElse(null); + List tasks = executionDAOFacade.getTaskModelsForWorkflow(workflowId); + Stream taskStream = + tasks.stream().filter(task -> !task.getStatus().isTerminal()); + Optional found = + taskStream + .filter(task -> task.getReferenceTaskName().equals(taskReferenceName)) + .findFirst(); + if (found.isPresent()) { + return found.get().toTask(); + } + // If no task is found, let's check if there is one inside an iteration + found = + tasks.stream() + .filter(task -> !task.getStatus().isTerminal()) + .filter( + task -> + TaskUtils.removeIterationFromTaskRefName( + task.getReferenceTaskName()) + .equals(taskReferenceName)) + .findFirst(); + + return found.map(TaskModel::toTask).orElse(null); } /** diff --git a/core/src/main/java/com/netflix/conductor/service/MetadataService.java b/core/src/main/java/com/netflix/conductor/service/MetadataService.java index 701055ef8..5edd42ef5 100644 --- a/core/src/main/java/com/netflix/conductor/service/MetadataService.java +++ b/core/src/main/java/com/netflix/conductor/service/MetadataService.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at @@ -16,11 +16,6 @@ import java.util.Map; import java.util.Optional; -import javax.validation.Valid; -import javax.validation.constraints.NotEmpty; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; - import org.springframework.validation.annotation.Validated; import com.netflix.conductor.common.metadata.events.EventHandler; @@ -29,6 +24,11 @@ import com.netflix.conductor.common.metadata.workflow.WorkflowDefSummary; import com.netflix.conductor.common.model.BulkResponse; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; + @Validated public interface MetadataService { diff --git a/core/src/main/java/com/netflix/conductor/service/MetadataServiceImpl.java b/core/src/main/java/com/netflix/conductor/service/MetadataServiceImpl.java index 7326ab62d..d48b95a42 100644 --- a/core/src/main/java/com/netflix/conductor/service/MetadataServiceImpl.java +++ b/core/src/main/java/com/netflix/conductor/service/MetadataServiceImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/core/src/main/java/com/netflix/conductor/service/TaskService.java b/core/src/main/java/com/netflix/conductor/service/TaskService.java index 7f4f3d0a6..c69c5135d 100644 --- a/core/src/main/java/com/netflix/conductor/service/TaskService.java +++ b/core/src/main/java/com/netflix/conductor/service/TaskService.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at @@ -15,10 +15,6 @@ import java.util.List; import java.util.Map; -import javax.validation.Valid; -import javax.validation.constraints.NotEmpty; -import javax.validation.constraints.NotNull; - import org.springframework.validation.annotation.Validated; import com.netflix.conductor.common.metadata.tasks.PollData; @@ -29,6 +25,10 @@ import com.netflix.conductor.common.run.SearchResult; import com.netflix.conductor.common.run.TaskSummary; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; + @Validated public interface TaskService { @@ -250,4 +250,11 @@ SearchResult search( */ ExternalStorageLocation getExternalStorageLocation( String path, String operation, String payloadType); + + String updateTask( + String workflowId, + String taskRefName, + TaskResult.Status status, + String workerId, + Map output); } diff --git a/core/src/main/java/com/netflix/conductor/service/TaskServiceImpl.java b/core/src/main/java/com/netflix/conductor/service/TaskServiceImpl.java index 5c07d5cff..0007bdf4e 100644 --- a/core/src/main/java/com/netflix/conductor/service/TaskServiceImpl.java +++ b/core/src/main/java/com/netflix/conductor/service/TaskServiceImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at @@ -139,6 +139,27 @@ public String updateTask(TaskResult taskResult) { return taskResult.getTaskId(); } + @Override + public String updateTask( + String workflowId, + String taskRefName, + TaskResult.Status status, + String workerId, + Map output) { + Task pending = getPendingTaskForWorkflow(workflowId, taskRefName); + if (pending == null) { + return null; + } + + TaskResult taskResult = new TaskResult(pending); + taskResult.setStatus(status); + taskResult.getOutputData().putAll(output); + if (StringUtils.isNotBlank(workerId)) { + taskResult.setWorkerId(workerId); + } + return updateTask(taskResult); + } + /** * Ack Task is received. * diff --git a/core/src/main/java/com/netflix/conductor/service/WorkflowBulkService.java b/core/src/main/java/com/netflix/conductor/service/WorkflowBulkService.java index 2c1ef0f7f..ca240b1a9 100644 --- a/core/src/main/java/com/netflix/conductor/service/WorkflowBulkService.java +++ b/core/src/main/java/com/netflix/conductor/service/WorkflowBulkService.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at @@ -14,13 +14,13 @@ import java.util.List; -import javax.validation.constraints.NotEmpty; -import javax.validation.constraints.Size; - import org.springframework.validation.annotation.Validated; import com.netflix.conductor.common.model.BulkResponse; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.Size; + @Validated public interface WorkflowBulkService { @@ -67,4 +67,23 @@ BulkResponse terminate( "Cannot process more than {max} workflows. Please use multiple requests.") List workflowIds, String reason); + + BulkResponse deleteWorkflow( + @NotEmpty(message = "WorkflowIds list cannot be null.") + @Size( + max = MAX_REQUEST_ITEMS, + message = + "Cannot process more than {max} workflows. Please use multiple requests.") + List workflowIds, + boolean archiveWorkflow); + + BulkResponse terminateRemove( + @NotEmpty(message = "WorkflowIds list cannot be null.") + @Size( + max = MAX_REQUEST_ITEMS, + message = + "Cannot process more than {max} workflows. Please use multiple requests.") + List workflowIds, + String reason, + boolean archiveWorkflow); } diff --git a/core/src/main/java/com/netflix/conductor/service/WorkflowBulkServiceImpl.java b/core/src/main/java/com/netflix/conductor/service/WorkflowBulkServiceImpl.java index c637b8bd9..fcbdbe3bc 100644 --- a/core/src/main/java/com/netflix/conductor/service/WorkflowBulkServiceImpl.java +++ b/core/src/main/java/com/netflix/conductor/service/WorkflowBulkServiceImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at @@ -30,9 +30,12 @@ public class WorkflowBulkServiceImpl implements WorkflowBulkService { private static final Logger LOGGER = LoggerFactory.getLogger(WorkflowBulkService.class); private final WorkflowExecutor workflowExecutor; + private final WorkflowService workflowService; - public WorkflowBulkServiceImpl(WorkflowExecutor workflowExecutor) { + public WorkflowBulkServiceImpl( + WorkflowExecutor workflowExecutor, WorkflowService workflowService) { this.workflowExecutor = workflowExecutor; + this.workflowService = workflowService; } /** @@ -164,4 +167,70 @@ public BulkResponse terminate(List workflowIds, String reason) { } return bulkResponse; } + + /** + * Removes a list of workflows from the system. + * + * @param workflowIds List of WorkflowIDs of the workflows you want to remove from system. + * @param archiveWorkflow Archives the workflow and associated tasks instead of removing them. + */ + public BulkResponse deleteWorkflow(List workflowIds, boolean archiveWorkflow) { + BulkResponse bulkResponse = new BulkResponse(); + for (String workflowId : workflowIds) { + try { + workflowService.deleteWorkflow( + workflowId, + archiveWorkflow); // TODO: change this to method that cancels then deletes + bulkResponse.appendSuccessResponse(workflowId); + } catch (Exception e) { + LOGGER.error( + "bulk delete exception, workflowId {}, message: {} ", + workflowId, + e.getMessage(), + e); + bulkResponse.appendFailedResponse(workflowId, e.getMessage()); + } + } + return bulkResponse; + } + + /** + * Terminates execution for workflows in a list, then removes each workflow. + * + * @param workflowIds List of workflow IDs to terminate and delete. + * @param reason Reason for terminating the workflow. + * @param archiveWorkflow Archives the workflow and associated tasks instead of removing them. + * @return bulk response object containing a list of succeeded workflows and a list of failed + * ones with errors + */ + public BulkResponse terminateRemove( + List workflowIds, String reason, boolean archiveWorkflow) { + BulkResponse bulkResponse = new BulkResponse(); + for (String workflowId : workflowIds) { + try { + workflowExecutor.terminateWorkflow(workflowId, reason); + bulkResponse.appendSuccessResponse(workflowId); + } catch (Exception e) { + LOGGER.error( + "bulk terminate exception, workflowId {}, message: {} ", + workflowId, + e.getMessage(), + e); + bulkResponse.appendFailedResponse(workflowId, e.getMessage()); + } + + try { + workflowService.deleteWorkflow(workflowId, archiveWorkflow); + bulkResponse.appendSuccessResponse(workflowId); + } catch (Exception e) { + LOGGER.error( + "bulk delete exception, workflowId {}, message: {} ", + workflowId, + e.getMessage(), + e); + bulkResponse.appendFailedResponse(workflowId, e.getMessage()); + } + } + return bulkResponse; + } } diff --git a/core/src/main/java/com/netflix/conductor/service/WorkflowService.java b/core/src/main/java/com/netflix/conductor/service/WorkflowService.java index bb760ac68..07fff88e0 100644 --- a/core/src/main/java/com/netflix/conductor/service/WorkflowService.java +++ b/core/src/main/java/com/netflix/conductor/service/WorkflowService.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at @@ -15,12 +15,6 @@ import java.util.List; import java.util.Map; -import javax.validation.Valid; -import javax.validation.constraints.Max; -import javax.validation.constraints.Min; -import javax.validation.constraints.NotEmpty; -import javax.validation.constraints.NotNull; - import org.springframework.validation.annotation.Validated; import com.netflix.conductor.common.metadata.workflow.RerunWorkflowRequest; @@ -32,6 +26,12 @@ import com.netflix.conductor.common.run.Workflow; import com.netflix.conductor.common.run.WorkflowSummary; +import jakarta.validation.Valid; +import jakarta.validation.constraints.Max; +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; + @Validated public interface WorkflowService { @@ -242,6 +242,19 @@ void terminateWorkflow( @NotEmpty(message = "WorkflowId cannot be null or empty.") String workflowId, String reason); + /** + * Terminate workflow execution, and then remove it from the system. Acts as terminate and + * remove combined. + * + * @param workflowId WorkflowId of the workflow + * @param reason Reason for terminating the workflow. + * @param archiveWorkflow Archives the workflow and associated tasks instead of removing them. + */ + void terminateRemove( + @NotEmpty(message = "WorkflowId cannot be null or empty.") String workflowId, + String reason, + boolean archiveWorkflow); + /** * Search for workflows based on payload and given parameters. Use sort options as sort ASCor * DESC e.g. sort=name or sort=workflowId:DESC. If order is not specified, defaults to ASC. diff --git a/core/src/main/java/com/netflix/conductor/service/WorkflowServiceImpl.java b/core/src/main/java/com/netflix/conductor/service/WorkflowServiceImpl.java index 99732a23a..bc6a700ee 100644 --- a/core/src/main/java/com/netflix/conductor/service/WorkflowServiceImpl.java +++ b/core/src/main/java/com/netflix/conductor/service/WorkflowServiceImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at @@ -196,6 +196,19 @@ public void deleteWorkflow(String workflowId, boolean archiveWorkflow) { executionService.removeWorkflow(workflowId, archiveWorkflow); } + /** + * Terminate workflow execution, and then remove it from the system. Acts as terminate and + * remove combined. + * + * @param workflowId WorkflowId of the workflow + * @param reason Reason for terminating the workflow. + * @param archiveWorkflow Archives the workflow and associated tasks instead of removing them. + */ + public void terminateRemove(String workflowId, String reason, boolean archiveWorkflow) { + workflowExecutor.terminateWorkflow(workflowId, reason); + executionService.removeWorkflow(workflowId, archiveWorkflow); + } + /** * Retrieves all the running workflows. * diff --git a/core/src/main/java/com/netflix/conductor/service/WorkflowTestService.java b/core/src/main/java/com/netflix/conductor/service/WorkflowTestService.java index 9dc3d334f..601c0aba8 100644 --- a/core/src/main/java/com/netflix/conductor/service/WorkflowTestService.java +++ b/core/src/main/java/com/netflix/conductor/service/WorkflowTestService.java @@ -1,5 +1,5 @@ /* - * Copyright 2023 Netflix, Inc. + * Copyright 2023 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/core/src/main/java/com/netflix/conductor/validations/ValidationContext.java b/core/src/main/java/com/netflix/conductor/validations/ValidationContext.java index 56fbb22d3..6bf5ed000 100644 --- a/core/src/main/java/com/netflix/conductor/validations/ValidationContext.java +++ b/core/src/main/java/com/netflix/conductor/validations/ValidationContext.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/core/src/main/java/com/netflix/conductor/validations/WorkflowTaskTypeConstraint.java b/core/src/main/java/com/netflix/conductor/validations/WorkflowTaskTypeConstraint.java index 99d070985..290d8692b 100644 --- a/core/src/main/java/com/netflix/conductor/validations/WorkflowTaskTypeConstraint.java +++ b/core/src/main/java/com/netflix/conductor/validations/WorkflowTaskTypeConstraint.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Netflix, Inc. + * Copyright 2022 Conductor Authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at @@ -22,10 +22,6 @@ import java.util.Optional; import javax.script.ScriptException; -import javax.validation.Constraint; -import javax.validation.ConstraintValidator; -import javax.validation.ConstraintValidatorContext; -import javax.validation.Payload; import org.apache.commons.lang3.StringUtils; @@ -35,6 +31,11 @@ import com.netflix.conductor.core.events.ScriptEvaluator; import com.netflix.conductor.core.utils.DateTimeUtils; +import jakarta.validation.Constraint; +import jakarta.validation.ConstraintValidator; +import jakarta.validation.ConstraintValidatorContext; +import jakarta.validation.Payload; + import static com.netflix.conductor.core.execution.tasks.Terminate.getTerminationStatusParameter; import static com.netflix.conductor.core.execution.tasks.Terminate.validateInputStatus; import static com.netflix.conductor.core.execution.tasks.Wait.DURATION_INPUT; @@ -262,7 +263,7 @@ private boolean isDoWhileTaskValid( String message = String.format( PARAM_REQUIRED_STRING_FORMAT, - "loopExpression", + "loopCondition", TaskType.DO_WHILE, workflowTask.getName()); context.buildConstraintViolationWithTemplate(message).addConstraintViolation(); @@ -272,7 +273,7 @@ private boolean isDoWhileTaskValid( String message = String.format( PARAM_REQUIRED_STRING_FORMAT, - "loopover", + "loopOver", TaskType.DO_WHILE, workflowTask.getName()); context.buildConstraintViolationWithTemplate(message).addConstraintViolation(); diff --git a/core/src/main/resources/META-INF/validation.xml b/core/src/main/resources/META-INF/validation.xml index 4c8ec2ce9..bdc4df27c 100644 --- a/core/src/main/resources/META-INF/validation.xml +++ b/core/src/main/resources/META-INF/validation.xml @@ -1,6 +1,6 @@