Commit Graph

2232 Commits

Author SHA1 Message Date
Gary Russell
df6674c2ec Fix DynamicPeriodicTrigger
- inconsistent use of internal `TimeUnit`
- `setPeriod()` applied the unit, but `getPeriod()` did not

This test failed...

```java
@Test
public void testTriggerConsistency() {
	final DynamicPeriodicTrigger trigger = new DynamicPeriodicTrigger(10, TimeUnit.SECONDS);
	trigger.setPeriod(trigger.getPeriod());
	assertThat(trigger.getPeriod(), equalTo(10_000));
}
```

Change the trigger to use `Duration` and deprecate the other methods.
2018-08-27 14:26:37 -04:00
Artem Bilan
aa371f59ff Ignore AggregatorTests.testAggPerfDefaultPartial
https://build.spring.io/browse/INT-MASTER-1165/

The test checks how much time have we spent for the process.
It's too hard to be precise in all the environment, especially on slow
CI servers

* Make some code style polishing in the `AggregatorTests`
2018-08-27 12:43:23 -04:00
Artem Bilan
d70df11975 PollerAdviceTests: synchronized list actions
https://build.spring.io/browse/INT-MASTERSPRING40-441

Even if we `stop()` a `SourcePollingChannelAdapter` that doesn't mean
that task-in-progress can't deliver its result to the source consumer.

* Wrap a list `add()` and iterator operations to avoid a
`ConcurrentModificationException`
2018-08-27 12:20:26 -04:00
Gary Russell
f4d5d84512 Fix DSL Flux Javadocs 2018-08-24 10:06:02 -04:00
Artem Bilan
9be9e63621 Upgrade to Spring AMQP 2.1 M2
* Add `@SuppressWarnings("serial")` for the `RequestMessageHolder`
* Use non-caching JMS CF for the Inbound endpoints in the `JmsTests`
* Make `AsyncGatewayTests extends ActiveMQMultiContextTests` to keep
embedded broker opened in between test methods
2018-08-20 17:35:48 -04:00
Artem Bilan
f9fe709881 Add Java DSL .fluxTransform(Function) operator (#2541)
* Add Java DSL `.fluxTransform(Function)` operator

For better interoperability with Reactor `Flux` from the
end-user perspective introduce an operator which could
call a target `Function` with integration data wrapped to the `Flux`
and expect a `Publisher<?>` result to continue the flow.
This way end-user just needs to implement a `Function` (or method)
to accept the `Flux` as an input and return some `Publisher`
after the sequence of reactive operators.

Such a new operator also allows a smooth integration with the
Spring Cloud Function, where it is just enough to lookup the function
in the catalog and inject it into this operator

* * Move `fluxTransform()` body to `Transformers` for cleaner context
distribution
2018-08-20 13:30:19 -04:00
Artem Bilan
8f639ad0d6 Move LeaderInitiators to later phase
There is a race condition when Zookeeper `LeaderInitiator` may start
earlier than `CuratorFramework` it depends on.
This is because both of them are configured for the same default `phase` (`0`)

* Make `LeaderInitiator` and `LockRegistryLeaderInitiator` to be started
in the `Integer.MAX_VALUE - 1000` phase by default - as late as possible
* Make `CuratorFrameworkFactoryBean` to start in the `Integer.MIN_VALUE + 1000`
phase - as early as possible
* Alight lifecycle properties from the `LeaderInitiatorFactoryBean` with
defaults in the `LeaderInitiator`
* Simplify a `LeaderListenerParser` to rely on the `LeaderInitiatorFactoryBean`

**Cherry-pick to 5.0.x**
2018-08-20 11:29:19 -04:00
Artem Bilan
5e47a6a9c4 INT-4517: Refactor beans in IntegrationRegistrar (#2537)
* INT-4517: Refactor beans in IntegrationRegistrar

JIRA: https://jira.spring.io/browse/INT-4517

The `IntegrationRegistrar` populates beans into the application context
too early and when the `allowBeanDefinitionsOverride` is disabled we
end up with the `BeanDefinitionOverrideException` just because end-user
beans are applied later.

* Move most of the bean definitions which can be overridden in the target
application from the `IntegrationRegistrar` into the
`DefaultConfiguringBeanFactoryPostProcessor`
* Revise their registration logic to be sure that some of them are
registered only once in the parent context nad others are registered
in the child context as well
* Refactor a `DslIntegrationConfigurationInitializer` do not register
an `IntegrationFlowDefinition.ReplyProducerCleaner` in the child context
one more time: it doesn't bring any local store within the current
child context
* Introduce a `NoBeansOverrideAnnotationConfigContextLoader` in tests
to ensure that in some test-cases we disallow an
`allowBeanDefinitionsOverride` as it is now in Spring Boot since it is
enabled by default in the Spring Framework

* Revernt DslIntegrationConfigurationInitializer changes

Regsiter all the required infrastructure beans in all the application
contexts to avoid class loader issue for `static` store access
2018-08-15 14:18:10 -04:00
Artem Bilan
60db7bc159 INT-4518: Channel late-binding in Messaging Anns
JIRA: https://jira.spring.io/browse/INT-4518

* Fix `BridgeFromAnnotationPostProcessor` do not resolve `outputChannel`
for the target `BridgeHandler`
* Rework logic in the `AbstractMethodAnnotationPostProcessor` to do not
resolve a `MessageHandler` bean from the `@Bean` method when we can
just check a method return type.
* Check `BeanDefinition` instead of real bean when we consult for
conditions

**Cherry-pick to 5.0.x**
2018-08-13 18:12:24 -04:00
Artem Bilan
e2b398ae10 Adapt to the latest Reactor 2018-08-13 11:32:00 -04:00
Artem Bilan
26229c9862 INT-4480: Use component type for ids in the flow (#2536)
* INT-4480: Use component type for ids in the flow

JIRA: https://jira.spring.io/browse/INT-4480

For better readability of bean names, e.g. from the metrics collectors,
generate them from the component type instead of their fully qualified
class names

* * Fix bean name for injection in the WebFluxDslTests
2018-08-09 15:01:41 -04:00
Artem Bilan
055e9a40db INT-4457: Add logAndReply() terminal operator
JIRA: https://jira.spring.io/browse/INT-4457

When an `IntegrationFlow` is reply-based (we expect a reply in the
beginning) and `log()` (or `wireTap()`) is used in the end, we are
forced to add an empty `bridge()` in the end to ensure a `replyChannel`
header routing

* Fix `IntegrationFlowDefinition` to add `enrichHeaders()` in the end
to populate a `nullChannel` as a `replyChannel` header if that is missed
in the request message headers.
This way we cover both use-cases when we expect reply from the flow and
when it is used as a one-way scenario
* Improve a `HeaderEnricher` do not create a new `Message` if there are
no new headers to add/remove
* Remove a note from the `dsl.adoc` about now redundant `bridge()` after
`log()`
* Resolve TODO in the `.handle()` paragraph

* Restore anonymous class in the MessageHistoryIntegrationTests:
Mockito can't mock/spy lambdas because they are `final` classes

* Introduce `IntegrationFlowDefinition.logAndReply()` operator

* Fix logging message

Doc Polishing
2018-08-07 11:35:31 -04:00
Gary Russell
34ac66df1c Ignore the Aggregator Performance test
Occasionally causes OOM on the CI server.
2018-08-01 17:43:25 -04:00
Gary Russell
23a3462d8b Add @NonNullApi where appropriate
Packages with `@Nullable` annotations need to have `@NonNulApi` at the package level.

There may be classes in these packages that have nullable arguments/returns that are
not currently marked as `@Nullable`. These will be fixed over time.

Also suppress JSR305 warnings when compiling tests.

* Polishing - PR Comments
2018-08-01 16:53:42 -04:00
Artem Bilan
55a43d37c8 Fix memory leak in MHistorConfig & MBeanExpHelper (#2531)
* Fix memory leak in MHistorConfig & MBeanExpHelper

The `MessageHistoryConfigurer` is a `BeanPostProcessor` which keeps a
store of the `TrackableComponent`.
Something similar we have with the `MBeanExporterHelper` and its local
stores populated by the `postProcessBeforeInitialization()`

* Implement `DestructionAwareBeanPostProcessor` in the
`MessageHistoryConfigurer` and `MBeanExporterHelper` to remove destroyed
beans from their caches

**Cherry-pick to 5.0.x**

* * Fix concurrency and checkstyle
* Apply Java 8 style for collections iterations
2018-07-27 15:50:09 -04:00
Artem Bilan
adbbca13fb INT-4513: Clean IntManageConf from removed beans
JIRA: https://jira.spring.io/browse/INT-4513

The `IntegrationManagementConfigurer` keeps metrics beans in its local
stores.
When we add beans at runtime, they are not removed from those caches
after their removal

* Implement `DestructionAwareBeanPostProcessor` in the `IntegrationManagementConfigurer`
and clean up caches according provided bean type and its name
* Improve `ManualFlowTests` and `FtpTests` to be sure that
`IntegrationManagementConfigurer` caches are cleared after destroying
 `IntegrationFlowRegistration`

**Cherry-pick to 5.0.x**
2018-07-27 13:32:08 -04:00
Gary Russell
bd0fd50313 INT-4514: Integration Graph, include dynamic flows
JIRA: https://jira.spring.io/browse/INT-4514

`getBeansOfType()` with eager init does not currently return late registered singletons.
We should not be eagerly initializing here anyway.

**cherry-pick to 5.0.x**
2018-07-27 12:45:09 -04:00
Artem Bilan
c44cd2b99b Upgrade to Reactor 3.2 M3, Fix FluxMessageChannel 2018-07-27 09:35:31 -04:00
Artem Bilan
8c03d72e2d INT-4510: Test no memory leak in FluxMessageCh
JIRA: https://jira.spring.io/browse/INT-4510

Related to https://github.com/reactor/reactor-core/issues/1290

The `Flux.publish()` and subsequent `connect()` doesn't fuse a subscriber
for the hooks flow is interrupted (complete, or error, or disconnect).
In this case the `FluxMessageChannel.publishers` store is not cleared
from the finished publishers

* Add test-case to check the `FluxMessageChannel.publishers` store after
finishing the stream
* Add `hide()` operator with TODO to remove when an appropriate Reactor
version is ready

**Cherry-pick to 5.0.x**
2018-07-27 09:31:51 -04:00
Artem Bilan
8b13b2861d Revert to errorStrategyContinue in FluxMessageChe
https://build.spring.io/browse/INT-MASTER-1134

According the latest released reactor-core-3.2.0.M2, there is no yet
a `.onErrorContinue()` operator.
We need to stick with the `.errorStrategyContinue()` for time being
2018-07-27 09:10:34 -04:00
Artem Bilan
da977941f8 INT-4509: Fix memory leak for static beans stores
JIRA: https://jira.spring.io/browse/INT-4509

To avoid a re-usage of the `AbstractReplyProducingMessageHandler`,
the `IntegrationFlowDefinition` and `AbstractStandardMessageHandlerFactoryBean`
have a `static Set<>` to store already used producers and check it for
newly provided.
These stores are not cleaned when beans are destroyed leading to memory
leaks

* Implements a `DisposableBean` for the `AbstractStandardMessageHandlerFactoryBean`
to remove its `replyHandler` from the `referencedReplyProducers` on
`destroy()`
* Introduce a `IntegrationFlowDefinition.ReplyProducerCleaner` - an
`DestructionAwareBeanPostProcessor` to clean up removing `MessageProducer`
from the `IntegrationFlowDefinition.REFERENCED_REPLY_PRODUCERS`

**Cherry-pick to 5.0.x**
2018-07-26 14:15:58 -04:00
Artem Bilan
1ee0639be4 Increase wait timeout in the AbsCorMHandlerTests
https://build.spring.io/browse/INT-MASTERSPRING40-414/
2018-07-26 09:47:20 -04:00
Artem Bilan
9d17e09f31 Upgrade to the latest Kotlin
* Fix more recursive generics on factory methods
See https://jira.spring.io/browse/INT-4458

**Cherry-pick to 5.0.x**
2018-07-26 09:11:55 -04:00
Artem Bilan
88c7646ed9 INT-4507: Use UNLINK in RedisMessageStore if any
JIRA: https://jira.spring.io/browse/INT-4507

* Add `RedisUtils` with the `isUnlinkAvailable()` to check the Redis
server version to be sure that `UNLINK` is available or not
* Use `RedisUtils.isUnlinkAvailable()` in the `RedisMessageStore` and
`RedisLockRegistry` when a removal functionality is performed
* Add `AbstractKeyValueMessageStore.doRemoveAll(Collection<Object> ids)`
for optimization
* Implement `doRemoveAll()` in the `RedisMessageStore` and
`GemfireMessageStore`

**Cherry-pick to 5.0.x**
2018-07-25 16:30:03 -04:00
Gary Russell
bebde260db INT-4506: Splitter: close stream and Closeables
JIRA: https://jira.spring.io/browse/INT-4506

Capture the actual splitter result in the `FunctionIterator and close it if necessary.

**cherry-pick to 5.0.x**

Add Closeable to proxy in test; remove AutoCloseable check.

Closeable extends AutoCloseable.

Fix javadocs; test for AutoCloseable instead of Closeable

Polishing - PR comments; tighten up API.

A `CloseableIterator` is now an `AutoCloseable` with an overridden
`close()`` (no exception) to avoid lint problem.

* Polishing omissions, code style and `@author`

**Cherry-pick to 5.0.x**
2018-07-25 13:16:48 -04:00
Artem Bilan
0d0605be78 INT-4381: MessageSources refactoring (#2517)
* INT-4381: MessageSources refactoring

JIRA: https://jira.spring.io/browse/INT-4381

* Make all the out-of-the-box `MessageSource` implementations based
on the `AbstractMessageSource`
* Fix `JdbcPollingChannelAdapterIntegrationTests` for sporadic failure
because of `fixed-rate` for the poller

* Fix HeaderEnricherTests race condition

The `errorChannel()` expect an error in the `testErrorChannel` after
`1000` ms, but at the same time the `poller` in configured for the
`3000` ms.

* Increase all the timeouts for replies
* Decrease a `fixed-delay` on the `poller`
* Some other code style polishing for the `HeaderEnricherTests`
2018-07-25 13:01:22 -04:00
Artem Bilan
3ff9645167 Fix FluxMessageChannel for the latest Reactor 2018-07-24 12:08:06 -04:00
Gary Russell
ec106984a2 Fix race condition in test 2018-07-19 10:27:12 -04:00
Artem Bilan
de9f8d7ccd INT-4501: Don't call getBean from BPP.setBFactory
JIRA: https://jira.spring.io/browse/INT-4501

The call to the `IntegrationFlowBeanPostProcessor#setBeanFactory`
happens during BPP creation.
The introduced call to `beanFactory#getBean` triggers a lot of bean
creations.
For those beans not all `BPP`s are applied.

* Obtain a `flowContext` bean in lazy-load manner

**Cherry-pick to 5.0.x**
2018-07-16 19:40:06 -04:00
Artem Bilan
1043b00996 Fix IntComponentSpec for ctx hooks
Since `IntegrationComponentSpec` is a `FactoryBean`, we need to care
about `Aware` and `init` & `destroy` hooks our selves or delegate
them through the `FactoryBean` wrapper

* Implement `InitializingBean` and `DisposableBean` on the
`IntegrationComponentSpec`
* Call the `Aware` hooks from the `IntegrationFlowBeanPostProcessor`

**Cherry-pick to 5.0.x**
2018-07-12 16:11:45 -04:00
Artem Bilan
a1f016a94c INT-4498: StreamUtils -> FileCopyUtils
JIRA: https://jira.spring.io/browse/INT-4498

* Use `FileCopyUtils` instead of `StreamUtils` in test-cases when we deal
with `InputStream` s and files resources.
* Fix reflection-based tests with AOP to use an `ArrayList` access
instead of `LinkedList` since an optimization in SF:
6d6aa72e8f

**Cherry-pick to 5.0.x and 4.3.x**
2018-07-09 13:39:56 -04:00
Gary Russell
26cfab579c INT-4491: (S)FTP inbound rotate dirs/servers
JIRA: https://jira.spring.io/browse/INT-4491

Add Rotating Server/Directory Polling Advice.

**cherry-pick to 5.0.x**

* Polishing - PR Comments.

* Polishing

* Polishing; revert `KeyDirectory`; WARN about `TaskExecutor` and `MessageSoureMutator`(s).

* More polishing - PR comments

* Apply stashed changes.

* Fix WARN log - the `SyncTaskExecutor` is wrapped.
2018-06-27 13:43:41 -04:00
Artem Bilan
69af967c78 INT-4488: Require @EnablePublisher
JIRA: https://jira.spring.io/browse/INT-4488

Since `PublisherAnnotationBeanPostProcessor` is quite expensive
(1.5x the CPU used by `MessagingAnnotationPostProcessor` in a simple
application)

* So not register a `PublisherAnnotationBeanPostProcessor` by default.
The `@EnablePublisher` has to be presented on the `@Configuration`
to allow the `@Publisher` AOP
* Change the `<int:annotation-config>` to require a new
`<int:enable-publisher>` sub-element for similar purpose - do not
register `PublisherAnnotationBeanPostProcessor` by default
2018-06-26 16:00:45 -04:00
Artem Bilan
13510df575 INT-4452: Expire immediately when group timeout<0
JIRA: https://jira.spring.io/browse/INT-4452

This is pretty typical in practice to get a `groupTimeout` to be
evaluated to a negative value: some business decisions, sensitive
calculations and so on.

* Treat any non-positive `groupTimeout` as a signal to expire group
immediately without scheduling.
Only `null` is considered as a signal do nothing for the current message
* Polishing for some tests for better performance - saves some execution
time
2018-06-26 12:41:48 -04:00
Artem Bilan
07c32ae93b INT-4489: MessageHistory: Allow runtime beans
JIRA: https://jira.spring.io/browse/INT-4489

Make `MessageHistoryConfigurer` as a `BeanPostProcessor` and apply
tracking logic to processed beans if it is already started.

**Cherry-pick to 5.0.x**
2018-06-22 13:55:20 -04:00
Artem Bilan
e6a35c4a60 INT-4487: Allow reconfiguring ARPMH.adviceChain
JIRA: https://jira.spring.io/browse/INT-4487

Currently the `AbstractReplyProducingMessageHandler` applies advices
only in the `afterPropertiesSet()` phase.
When we use bean references for `MessageHandler`s in Java DSL, the
`.advice()` provided in the flow definition is not applied to the
`AbstractReplyProducingMessageHandler`.

* For consistency with the endpoint configured by the DSL definition,
override and reconfigure advices in the `AbstractReplyProducingMessageHandler`
bean reference during DSL parsing and processing.

Fix `TwitterSearchOutboundGatewayParserTests` for the proper assert
2018-06-22 13:06:18 -04:00
Gary Russell
0735ddb0ed INT-4390: Fix tangle betweewn dsl and dsl.context
JIRA: https://jira.spring.io/browse/INT-4390

Move IFBPP and lifecycle advice to `....dsl.context`.
2018-06-20 12:33:37 -04:00
Artem Bilan
5a362b62ff Destroy RmiInboundGateway.RmiServiceExporter (#2481)
* Destroy RmiInboundGateway.RmiServiceExporter

The internal instance `RmiServiceExporter` of the `RmiInboundGateway`
has to be destroyed together with the outer instance to unbind `service`
from the RMI registry

* Perform some polishing for the `RmiInboundGateway` and optimize
a `AbstractInboundGatewayParser` for late channels binding

* * Polishing some tests
* Expose getters for channels on the `MessagingGatewaySupport`
* Fix RMI tests to use random port
2018-06-15 08:40:11 -04:00
Artem Bilan
da53ed6838 INT-4485: Don't register bean twice for DSL Specs
JIRA: https://jira.spring.io/browse/INT-4485

The `IntegrationFlowBeanPostProcessor` performs extra bean registration
for the `IntegrationComponentSpec.get()` result.
Essentially it is going to be the same object in the end, but during
bean registration phase we end up with names conflict.

* Remove an explicit `registerComponent()` for the
`IntegrationComponentSpec.get()`
* Modify `CorrelationHandlerTests` for all possible usage for the
`MessageChannelSpec`, which is essentially a `FactoryBean`

**Cherry-pick to 5.0.x**
2018-06-12 10:11:41 -04:00
Artem Bilan
85bc183849 INT-4486: Properly implement stop(Runnable)
JIRA: https://jira.spring.io/browse/INT-4486

The `SmartLifecycle.stop(Runnable callback)` must always call the
`callback` in the end independently of the internal state

* Revise all the `SmartLifecycle` implementations for the proper
`callback` handling

**Cherry-pick to 5.0.x and 4.3.x**
2018-06-11 17:51:20 -04:00
Gary Russell
88120a667e INT-4482: AMQP: Fix Double ErrorMessage
JIRA: https://jira.spring.io/browse/INT-4482

The outer try/catch sends an `ErrorMessage` for all exceptions; it should
only do so for `MessageConversionException`. Integration flow exceptions
will have been already handled by `MessageProducerSupport`.

Also, populate the raw message header consistently - previously it only
was populated for flow exceptions. Although the LEFE contains the raw
message, it should be in the `ErrorMessage` header for consistency.

**cherry-pick to 5.0.x, 4.3.x**

* Polishing - PR Comments
2018-06-05 16:34:58 -04:00
Artem Bilan
f4809aa997 INT-4424: No @Inherited on method annotations
JIRA: https://jira.spring.io/browse/INT-4424

* Polishing for `phase` JavaDocs
2018-06-05 09:44:49 -04:00
Artem Bilan
94cded7575 Remove dependant beans recursively
https://build.spring.io/browse/INT-MASTER-1058/

When we destroy manually registered `IntegrationFlow`, we need to
count with sub-flows and iterate all the dependant beans recursively
for full flow removal

**Cherry-pick to 5.0.x**
2018-06-01 09:45:30 -04:00
Gary Russell
997b07afed INT-4476: Fall back for ID and Timestamp Headers
JIRA: https://jira.spring.io/browse/INT-4476

When mapping outbound headers, if the `AmqpHeaders` `ID` and `Timestamp` headers
are not present, fall back to mapping the `MessageHeaders` variants (if present).

Also fix some PDF overflows.
2018-05-31 17:18:39 -04:00
Artem Bilan
03a89337cb INT-4474: ConsumerEndpointFactoryBean: Fix phase
JIRA: https://jira.spring.io/browse/INT-4474

* Populate proper `Integer.MIN_VALUE` phase for non-`PollingConsumer`s
in the `ConsumerEndpointFactoryBean`

**Cherry-pick to 5.0.x and 4.3.x**
2018-05-31 16:50:34 -04:00
Artem Bilan
17e794d2c8 INT-4471: PubSubChannel: Add errorHandler warn (#2459)
* INT-4471: PubSubChannel: Add errorHandler warn

JIRA: https://jira.spring.io/browse/INT-4471

* When an `Executor` is not provided, log warn that the provided
`ErrorHandler` is ignored.

**Cherry-pick to 5.0.x and 4.3.x**

* * Polish warn message
2018-05-31 15:25:38 -04:00
Artem Bilan
9a88140fb3 Fix LambdaMessageProcessor for Map payload
JIRA: https://jira.spring.io/browse/INT-4478

When we use a `GenericHandler` and an incoming payload is a `Map`, we
copy it into both arguments into the `Object` for the payload
and `Map` for the headers.
This way we lose headers in the target lambda

* Check a size of arguments on the target lambda and don't set a
payload into the `Map` argument if we have more than 1 arguments

**Cherry-pick to 5.0.x**
2018-05-31 15:18:44 -04:00
Gary Russell
73dbdb80be INT-4477: Add getRole() to LeaderInitiator Context
JIRA: https://jira.spring.io/browse/INT-4477

When running multiple roles, it is useful to be able to determine the
role for a particular context, e.g. in an event.

* Docs

**cherry-pick to 5.0.x**
2018-05-31 10:54:35 -04:00
Artem Bilan
c9faf3c8ce Fix LockRegLeaderIn for interrupted Thread.sleep (#2455)
* Fix LockRegLeaderIn for interrupted Thread.sleep

https://build.spring.io/browse/INT-FATS5IC-517

If current thread is interrupted, the `Thread.sleep()` interrupts
immediately.
In the catch block of the main loop in the `LockRegistryLeaderInitiator`
we have such a dangerous `sleep()` and don't restart election in this
candidate any more

* Move `Thread.sleep()` to else after checking the current thread for
interrupted state
* Remove `LongRunningIntegrationTest` rule from the
`RedisLockRegistryLeaderInitiatorTests` since it now works much faster
after proper `busy-wait` handling

**Cherry-pick to master**

* Ignore interruption on the sleep i catch and move on with loop
2018-05-30 15:23:26 -04:00
Gary Russell
324c54d8ef Remove use of deprecated ChannelInterceptorAdapter
Deprecated in favor of default methods on `ChannelInterceptor`.

* Fix race in RouterConcurrencyTest; no assertion on executor shutdown; increase time.
2018-05-24 15:11:11 -04:00