Commit Graph

253 Commits

Author SHA1 Message Date
NaccOll
4d08e11903 Add Redis lock periodic renewal
Although `RenewableLockRegistry` provides a renew interface, it is inconvenient for users.
Developers hope to have a lock that can be automatically renewed.
On the one hand, it can avoid subsequent failures caused by locks that will not expire when abnormal exits,
and on the other hand, it can avoid unlock failures caused by lock expired.

* Add `RenewableLockRegistry.setRenewalTaskScheduler()` and when it is set, schedule a `renew()` script periodically
when lock is acquired  from Redis with `1/3` of `expireAfter`
* Test and document the feature
2024-10-17 16:49:14 -04:00
Artem Bilan
7d091cecf4 Fix Checkstyle violation in the RedisLockRegistry 2024-10-08 12:45:54 -04:00
Alexandr
1d4fbbc85e GH-9540: Add RedisLockRegistry.idleBetweenTries property
Fixes: https://github.com/spring-projects/spring-integration/issues/9540
2024-10-08 12:28:12 -04:00
alexpeelman
07085a17ae GH-9401: RedisLockRegistry: use lock() instead of tryLock() for lifecycle
Fixes: #9401

Switched `tryLock()` with `lock()` in `RedisLockRegistry.runRedisMessageListenerContainer()` method for correct synchronization.

**Auto-cherry-pick to `6.3.x` & `6.2.x`**
2024-08-20 16:08:48 +00:00
Eddie Cho
53445fe771 GH-9291: Enhanced unlock() method of JdbcLock to verify successful unlocking
Fixes: #9291

* Modify `unlock()` method of `JdbcLock`: if the lock ownership can not be removed due to data expiration, a `ConcurrentModificationException` should be thrown.
* Modify `unlock()` method of `RedisLock`: if the lock ownership can not be removed due to data expiration, a `ConcurrentModificationException` should be thrown.
* Maintain test cases
* Document the new behavior
2024-07-02 15:48:07 -04:00
Artem Bilan
c155d5d418 Add EmptyLineSeparator Checkstyle rule
* Support "blank lines around" via `spring-framework.xml` IDEA config
* Fix all the Checkstyle violations
2024-03-27 16:54:25 -04:00
Neville Bonavia
62fd3e6c20 GH-8869: Fix NPE in RedisLockRegistry.setExecutor
Fixes: #8869

Do not set the `redisMessageListenerContainer`'s executor in the setter method
since the Redis Message Listener container is not initialised during configuration due to lazy loading

**Cherry-pick to `6.2.x` & `6.0.x`**
2024-01-30 13:01:19 -05:00
Roman Zabaluev
9bd8001a61 GH-8803: RedisLockRegistry: Log for lock acquired
Fixes: #8803

Would be great to have an `Acquired lock; RedisLock...`  logging message as we already have `Released lock; RedisLock ...`

* Improve `RedisLockRegistry.RedisLock.tryRedisLock()` to emit `Acquired lock; RedisLock...` debug message

**Cherry-pick to `6.0.x`**
2023-12-11 17:06:21 -05:00
Myeonghyeon-Lee
50c53e08aa GH-8730: Fix isAcquiredInThisProcess to use localLock
The `ExpirableLockRegistry.expireUnusedOlderThan()` uses a query to the target store by mistake.
The logic of this API is indeed about the local cache for those lock instances.
We cannot effect any other processes with this cache. 
And even if we remove our local instance while it is locked in other process, 
that doesn't mean that on the next `obtain()` call, when we got a fresh local instance, we will be able to acquire a lock in target store.

* Fix `isAcquiredInThisProcess()` to check only `localLock.isLocked()`

**Cherry-pick to `6.1.x` & `6.0.x`**
2023-09-18 10:39:37 -04:00
Eddie Cho
ba6d35d123 GH-8699: Fix Issue of removeLockKey()
In the current code, an `IllegalStateException` might be thrown from the try block while invoking the `removeLockKeyInnerUnlink()` method, especially when caused by key expiration (resulting in `unlinkResult == false`).

This triggers the check block, which incorrectly sets the `unlinkAvailable` flag to `false`, even if the Redis server supports the unlink operation.

As a consequence, the subsequent `removeLockKeyInnerDelete()` method is invoked when it should not be.

* `IllegalStateException` should not be thrown from try block
* Add a comment and fix Checkstyle violations

**Cherry-pick to `6.1.x` & `6.0.x`**
2023-08-15 13:48:03 -04:00
EddieChoCho
0450a323ec GH-8699: Atomic Redis script for unlock()
Expected Behavior

Using a single Lua script to verify ownership of the lock and remove it.

Current Behavior

`unlock()` method of `RedisLock` uses two separate Redis operations:

    * `isAcquiredInThisProcess()`` method executes a `GET` operation to verify if the lock is owned by the process.
    * `removeLockKey()`` method executes `UNLINK/DEL` operation to remove the lock.

* The `removeLockKeyInnerUnlink()`, and `removeLockKeyInnerDelete()`
methods will execute a script both verify ownership of the lock and remove it.

**Cherry-pick to `6.1.x` & `6.0.x`**
2023-08-14 10:44:57 -04:00
Artem Bilan
43473836ef Remove unused ThreadLocal from RedisStoreMSource (#8663)
* Remove unused ThreadLocal from RedisStoreMSource

The `RedisStoreMessageSource` relies on an `IntegrationResourceHolder`
for a while already.
Its internal `ThreadLocal` is just out of use.

* Remove that `resourceHolder` property and related methods to interact with it.
* Mention the `IntegrationResourceHolder` and `store` attribute in the `redis.adoc`

* Fix language in Docs

Co-authored-by: Gary Russell <grussell@vmware.com>

---------

Co-authored-by: Gary Russell <grussell@vmware.com>
2023-06-28 13:40:48 -04:00
Christian Tzolov
c38ed96ee9 GH-8643: Replace synchronized with Lock
Fixes https://github.com/spring-projects/spring-integration/issues/8643

* First pass - trivial synchronized blocks
  - Convert the "trivial" `synchronized` block into `ReentrantLock`.

* fix checkstyle

* use blocking lock

* Secon pass - handle multi-lock cases

* javadoc + year

* addres first batch of review suggestions

* fix checkstyle issues

* fix the mqtt parent/child lock monitor sharing

* fix the mqtt parent/child lock monitor sharing, v2

* patch the stomp test
2023-06-21 13:25:45 -04:00
Artem Bilan
4db9bad50d GH-8642: Revise executors in the project (#8647)
* GH-8642: Revise executors in the project

Fixes https://github.com/spring-projects/spring-integration/issues/8642

* Rework some `Executors.newSingleThreadExecutor()` to `ExecutorServiceAdapter(new SimpleAsyncTaskExecutor())`
* Expose `TaskExecutor` setters; deprecate `ExecutorService`-based
* Some other code clean up in the effected classes: `LogAccessor`, no `synchronized` in critical blocks
* Give a meaningful prefix for default threads in the context of components, e.g. `SubscribableRedisChannel` - `getBeanName() + "-"`

* * Fix `PostgresChannelMessageTableSubscriberTests` for
`PostgresSubscribableChannel` initialization to let it create
its internal `Executor`

* Use an `AsyncTaskExecutor` injection instead of `ExecutorServiceAdapter` wrapping

* Fix `LockRegistryLeaderInitiatorTests` for `taskExecutor` injection

* Bring back `LockRegistryLeaderInitiator.setExecutorService()`
as an accident after property auto-renaming
2023-06-14 13:33:46 -04:00
Artem Bilan
32e34bf2ec GH-5871: Add missed order attr to XSDs (#8624)
* GH-5871: Add missed `order` attr to XSDs

Fixes https://github.com/spring-projects/spring-integration/issues/5871

* * Fix `spring-integration-xml.xsd` for duplicates
2023-05-22 11:59:47 -04:00
abilan
22d47e72e9 Use Java text blocks for scripts in code
* Fix `WebServiceInboundGatewayParserTests` for reply timeout for
replies which never come accoridn the test logic
2023-03-28 18:50:34 -04:00
Artem Bilan
1bec420fd1 Do not block by default (#8580)
Currently, many timeouts in the project are like `-1` or other negative value
with a meaning to wait indefinitely.

According to distributed systems design and bad demo developing experience
it is not OK to block forever.

* Rework most of the timeouts in the framework to be `30` seconds.
Only one remained as `1` seconds is a `PollingConsumer` where it is
better to not block even for those 30 seconds when no messages in the queue,
but let the polling task be rescheduled.
* Remove the `MessagingGatewaySupport.replyTimeout` propagation down to the
`PollingConsumer` correlator where it was a `-1` before and blocked
the polling thread on the `Queue.poll()`.
This fixed the problem with a single thread in a pool for auto-configured `TaskScheduler`.
Now with 1 seconds wait time we are able to switch to other scheduled tasks
even with only 1 thread in the pool
2023-03-21 17:43:00 -04:00
Anton Gabov
d7150685b1 RedisLockRegistry: Don't expire not acquired lock
Fix race condition, when methods `RedisLockRegistry#expireUnusedOlderThan` and `RedisLockRegistry#obtain` are executed successively. 

It's possible to delete the lock from `RedisLockRegistry#expireUnusedOlderThan` method, when lock is created but is not acquired (`RedisLock#getLockedAt = 0`)
It can lead to the situation, when `RedisLockRegistry#obtain` returns multiple locks with the same redis-key, which shouldn't happen at all.

* Skip locks from expiration when their `lockedAt == 0` - new, not acquired yet.

**Cherry-pick to `6.0.x` & `5.5.x`**
2023-03-15 11:18:03 -04:00
abilan
9dd9f08181 Use switch expression; some other clean up 2023-01-13 16:00:19 -05:00
abilan
7864658d01 GH-3686: Apply SF editor config
Fixes https://github.com/spring-projects/spring-integration/issues/3686

* Add `src/idea` with respective editor config for IntelliJ IDEA.
Must be imported into an IDE
* Add `src/eclipse` with respective editor config for Eclipse/STS
* Reformat imports in source code according a new editor config
2022-11-14 10:55:21 -05:00
Artem Bilan
695e1563ed GH-3888: Fix NPE in the RedisLockRegistry.destroy() (#3889)
* GH-3888: Fix NPE in the `RedisLockRegistry.destroy()`

Fixed https://github.com/spring-projects/spring-integration/issues/3888

When `RedisLockType.SPIN_LOCK` (default), the `RedisLockRegistry.destroy()`
causes an NPE on the `redisMessageListenerContainer` since pub-sub is not used
in a busy-spin mode

* Check for `redisMessageListenerContainer` before calling its `destroy()`

**Cherry-pick to 5.5.x**

* * Reset properties in the `RedisLockRegistry` after `destroy()`
2022-09-20 14:17:37 -04:00
Artem Bilan
15e89c3b62 Rework infra logic onto IntegrationProperties (#3881)
* Rework infra logic onto IntegrationProperties

The `Properties` bean has been deprecated since `5.5`

* Register a default `integrationGlobalProperties` as a `IntegrationProperties`
* Fix respective usages from the `Properties`

* * Remove unused constant from the `IntegrationContextUtils`

* * Fix language in the `whats-new.adoc`

Co-authored-by: Gary Russell <grussell@vmware.com>

Co-authored-by: Gary Russell <grussell@vmware.com>
2022-09-06 10:50:34 -04:00
Artem Bilan
5572c2161d Fix deprecations around ListenableFuture (#3865)
* Fix deprecations around ListenableFuture

SF has deprecated a `ListenableFuture` and API around it

* Migrate to `CompletableFuture` everywhere a `ListenableFuture` has been used
* Suppress a deprecation for `ListenableFuture` keeping the functionality until the next version
* Resolve deprecations nad removals from the latest Spring for Apache Kafka
* Fix documentation for the `ListenableFuture` in favor of `CompletableFuture`

NOTE: the AMQP module is left as is until `ListenableFuture` deprecation is resolved in Spring AMQP

* * Restore some `ListenableFuture` test for messaging gateway
2022-07-28 09:32:01 -04:00
unseok kim
cf6ce961a2 GH-3805: Introduce RedisLockRegistry.RedisLockType mode
Fixes https://github.com/spring-projects/spring-integration/issues/3805

The Redis Pub-Sub doesn't work in all the environment, therefore there has to
be a choice to use old busy-spin algorithm

* Change to select between spinLock method and pub-sub method
* Make spinLock as a default one to let the `RedisLockRegistry` work everywhere
* Fix javadoc, convention, lazy init
* Fix javadoc, convention
* Code clean up and docs for `RedisLockType` feature

**Cherry-pick to 5.5.x**
2022-06-08 13:15:30 -04:00
Artem Bilan
70587f5e2f Upgrade some deps; fix compatibility with them
* Upgrade to the latest Spring portfolio stack;
fix tests and effected classes
* The move to the latest Micrometer does not affect code base
2022-03-08 10:08:36 -05:00
Unseok Kim
291fe34610 GH-3716 Fix wait for init redisMsgListenContainer
Fixes https://github.com/spring-projects/spring-integration/issues/3716

If the `redisMessageListenerContainer` is starting, waiting for it to complete without doing `subscribeUnlock()`

* Introduce `isRunningRedisMessageListenerContainer` state since the `running` in the `RedisMessageListenerContainer` is set in the beginning of the `start()` misleading on the concurrent calls to the `RedisLockRegistry`

**Cherry-pick to `5.5.x`**
2022-02-08 10:08:23 -05:00
Unseok Kim
6c769cab37 GH-3700: Fix Redis lock retry until expiration
Fixes https://github.com/spring-projects/spring-integration/issues/3700

Fixed a case where lock acquisition attempt was abandoned earlier than expected time.
If a vm uses `tryLock()` and another vm unlock it, it will wake up with an unlock message and try to acquire the lock, 
but if it fails(the other vm obtain lock), vm will return false.
2022-01-04 09:16:10 -05:00
Artem Bilan
bb9dd89286 Fix RedisLockRegistry Sonar smells
* Remove redundant `subscribeLock()` method
* Rework `lock()` and `lockInterruptibly()` logic in favor of `while (true) {`
to avoid "empty `while()`" smell
2021-12-16 13:49:15 -05:00
Artem Bilan
30bb8467b4 Fix Checkstyle violation 2021-12-14 21:12:41 -05:00
Artem Bilan
2d752894cd Fix UNLINK/DEL logic in the RedisLockRegistry
See review: https://github.com/spring-projects/spring-integration/pull/3691#issuecomment-994124360
2021-12-14 19:50:49 -05:00
unseok kim
3c32daa25a GH-3690: Use pub-sub in RedisLockReg for unlocks
Fixes https://github.com/spring-projects/spring-integration/issues/3690

Replace spinLock with pub-sub

rename and add comment

* change remove timing for 'notifyMap'
* use unlink
* remove DUMMY_CALLABLE

* Clean up code style
2021-12-14 12:05:57 -05:00
Unseok Kim
db611028da GH-3672: Clean up Jdbc & ZK LockRegistry caches
Fixes https://github.com/spring-projects/spring-integration/issues/3672

* Clean up `JdbcLockRegistry`, `ZookeeperLockRegistry` cache automatically 
* setCapacity(int capacity) to cacheCapacity(int capacity)
* field rename `capacity`to `cacheCapacity`, add static
2021-11-11 16:36:27 -05:00
Unseok Kim
3c812440cf Change RedisLockRegistry cache to 100K
1_000_000 of cache entries take too much memory
2021-11-11 10:54:56 -05:00
unseok kim
e51513230a GH-3655: Add automatically delete for Redis Locks
Fixes https://github.com/spring-projects/spring-integration/issues/3655

* support automatically clean up cache
* RedisLockRegistry.capacity desc
2021-11-10 14:24:53 -05:00
Artem Bilan
fe57fd281c Checkstyle changes
* Upgrade to Checkstyle 9.0
* apply some JavaDocs rules
* Fix JavaDocs rules violations
* Some other minor clean up in the affected classes
2021-09-28 11:55:25 -04:00
trungPa
9e512186ed GH-3549: Fix minor SonarQube smells
Fixes https://github.com/spring-projects/spring-integration/issues/3549
2021-07-23 11:07:39 -04:00
trungPa
9c718c37a6 GH-3424: Refactor to use logging methods from LogAccessor
Fixes https://github.com/spring-projects/spring-integration/issues/3424

* Use `LogMessage.format()` for lazily formatting

* Fix some logging statements in `JdbcChannelMessageStore`
2021-07-19 11:30:01 -04:00
Artem Bilan
8763c95622 GH-3469 New Sonar smell & volatile busyWaitMillis
Fixes https://github.com/spring-projects/spring-integration/issues/3469

* Fix new Sonar smells
* Mark `LockRegistryLeaderInitiator.busyWaitMillis` as `volatile`
so runtime changes (e.g. `RedisLockRegistryLeaderInitiatorTests`)
will make an immediate effect
2021-01-21 14:55:14 -05:00
Artem Bilan
51e240b761 GH-3439: Revise error handling in RedisStreamMP
Fixes https://github.com/spring-projects/spring-integration/issues/3439

The latest Spring Data Redis has introduced an `onErrorResume` function
option for the `StreamReceiver` and this one is now recommended way
to handle errors in the `Flux` from this receiver

* Expose all the `StreamReceiver.StreamReceiverOptionsBuilder` option
onto the `ReactiveRedisStreamMessageProducer`, including `onErrorResume`
* Have a default function as it was before - send into an error channel
supporting (n)ack in the failed message based on the failed record
* Make new setters mutually exclusive with an explicit `StreamReceiver.StreamReceiverOptions`

* Doc polishing
2021-01-20 13:36:35 -05:00
Artem Bilan
4909f030a1 GH-3434: Optimize unlinkAvailable in Redis
Fixes https://github.com/spring-projects/spring-integration/issues/3434

Each `RedisLock` has their own `unlinkAvailable` property
therefore we try to `unlink` on every unlock call and also log a WARN
about unavailability of this command in Redis, plus exception

* Move `unlinkAvailable` property to the `RedisLockRegistry` level
to have a check only once on a first `unlock()` call
* Move the whole exception logging onto the DEBUG level, leaving the WARN
only with the `ex.getMessage()`
* Optimize logging the same way in the `RedisMessageStore`

Cherry-pick to `5.3.x & 5.2.x`
2020-12-01 14:50:51 -05:00
Artem Bilan
7eb07344cc GH-3428: Make Kotlin dependency optional again
Fixes https://github.com/spring-projects/spring-integration/issues/3428

The Kotlin Gradle plugin starting with Kotlin `1.4` adds a standard
Kotlin lib into `compile` scope fully ignoring an `optional` variant.
See more info here: https://kotlinlang.org/docs/reference/using-gradle.html#dependency-on-the-standard-library

* Add `kotlin.stdlib.default.dependency=false` into `gradle.properties`
to rely only on the explicit dependency definitions in the project config
* Remove explicit Kotlin deps from test scope in the target modules since
it is declared globally for all the modules
* Fix author emails in the `publish-maven.gradle` to their VMware variants
* Remove usage of `org.jetbrains.annotations` in favor of `@Nullable`
from Spring Framework
2020-11-11 11:04:24 -05:00
Artem Bilan
0331933c16 Rely on MProducerSupport.active for Flux (#3423)
* Rely on `MProducerSupport.active` for `Flux`

* Fix `MessageProducerSupport` to extract an `active` flag and set it before
`isRunning` - the `Flux` subscription relies on the `takeWhile()`
where in case of `autoStartup = false` we will never start consume because
it is set to `true` already after `doStart()`
* Refactor all the `MessageProducerSupport` implementation with similar
`active` state to use already one from the super class

**Cherry-pick to 5.3.x**

* * Remove `MessageProducerSupport.setActive()`
to not let to mutate it from the implementations
* Set `active` to `false` in the `destroy()`
* Clean up and fix typos in the affected `JmsMessageDrivenEndpoint`

* * Pull `active` flag down to the `AbstractEndpoint`
* Set `active = true` in the `start()` before calling `doStart()`
* Do same for `active = false` in the `stop()`
* Clean up `AbstractEndpoint` impls to not call `doStart/doStop` for nothing
* Refactor endpoints to rely on the `active` state from the `AbstractEndpoint`
not their own
2020-11-06 13:51:03 -05:00
Artem Bilan
ac6a0982e5 Fix deprecations from Spring's StringUtils
* Use `LogAccessor` in the `XmlValidatingMessageSelector`
2020-10-28 16:33:51 -04:00
rohan mukesh
51ebf40a5f Add Docs for Redis Stream Channel adapters
* Fix JavaDoc for the `ReactiveRedisStreamMessageProducer.setExtractPayload()`
2020-10-28 13:43:15 -04:00
rohan mukesh
b1a383060d Add Error Handling to RedisStreamMessageProducer
* Use 'onErrorContinue' to continue receiving messages from Stream
* Send an `ErrorMessage` to the provided `errorChannel` (if any)
* And `@Nullable` to some `MessageProducerSupport` API which definitely
may accept `null`
* Extract common `buildMessageFromRecord()` method in the `ReactiveRedisStreamMessageProducer`,
so all the headers from the stream `Record` are carried to the message independently of the
 record state - normal send or error sending
2020-10-14 13:36:01 -04:00
rohan mukesh
6d6f53fa87 Fix r2bdc componentType; Redis Streams ack issue
The R2DBC channel adapters have wrong componentType

* Fix R2DBC component type to not mention `reactive-`: they are reactive by R2DBC definition

The `ReactiveRedisStreamMessageProducer` calls ack() explicitly
when populates `IntegrationMessageHeaderAccessor.ACKNOWLEDGMENT_CALLBACK` header,
but must provide an implementation of `SimpleAcknowledgment` instead

* Fix `ReactiveRedisStreamMessageProducer` to populate the proper
`IntegrationMessageHeaderAccessor.ACKNOWLEDGMENT_CALLBACK` header and in the proper moment
* Fix `ReactiveRedisStreamMessageProducerTests` to verify that `autoAck=false` works as expected
together with the `IntegrationMessageHeaderAccessor.ACKNOWLEDGMENT_CALLBACK` header functionality
2020-10-07 17:06:49 -04:00
Artem Bilan
c7ff99a4e8 Use LogAccessor from SF
* Change main classes to use a `LogAccessor` API to simplify code flow
* Fix tests according `LogAccessor` property
* Fix some Sonar smells
2020-10-06 13:56:50 -04:00
Artem Bilan
3fb6567a1f Fix new Sonar smells 2020-08-21 11:37:43 -04:00
Artem Bilan
750d721437 Fix some Sonar smells 2020-08-20 16:08:18 -04:00
Attoumane
3cb13af813 More tests for Redis Stream support
Related to https://github.com/spring-projects/spring-integration/issues/3226
2020-08-11 09:30:09 -04:00