-
Notifications
You must be signed in to change notification settings - Fork 12
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Per-environment configuration for ServerEnvironment
parts
#1274
Per-environment configuration for ServerEnvironment
parts
#1274
Conversation
Codecov Report
@@ Coverage Diff @@
## master #1274 +/- ##
============================================
- Coverage 91.12% 91.07% -0.06%
- Complexity 4696 4710 +14
============================================
Files 605 606 +1
Lines 14920 14992 +72
Branches 852 851 -1
============================================
+ Hits 13596 13654 +58
- Misses 1057 1072 +15
+ Partials 267 266 -1 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@serhii-lekariev please see my comments.
Also, as you change is an API change, please make sure to bump the own library version.
* @param <P> | ||
* the type of value | ||
*/ | ||
public class EnvironmentDependantValue<P> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is way too complex for a name. Please think of some other options; if it's difficult to pick, leave a comment with any ideas that come to your mind. We'll then discuss.
Also, this class should be final
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ConfigurableValue
is too generic, but sort of true?
It's a wrapper around two values, both of which may be absent, and those values have "production" and "testing" semantics, which I would call two different environments.
server/src/main/java/io/spine/server/EnvironmentDependantValue.java
Outdated
Show resolved
Hide resolved
public class EnvironmentDependantValue<P> { | ||
|
||
private @Nullable P productionValue; | ||
private final UnaryOperator<P> productionWrappingFunction; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please shorten the name.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this resolved?
server/src/main/java/io/spine/server/EnvironmentDependantValue.java
Outdated
Show resolved
Hide resolved
server/src/test/java/io/spine/server/EnvironmentDependantValueTest.java
Outdated
Show resolved
Hide resolved
server/src/test/java/io/spine/server/EnvironmentDependantValueTest.java
Outdated
Show resolved
Hide resolved
} | ||
|
||
@Test | ||
@DisplayName("wrap test storage") | ||
void wrapTestStorage() { | ||
ServerEnvironment serverEnv = ServerEnvironment.instance(); | ||
StorageFactory testStorage = InMemoryStorageFactory.newInstance(); | ||
serverEnv.configureStorageForTests(testStorage); | ||
serverEnv.configureStorage().tests(testStorage); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would rather have something like
serverEnv.useStorageFactory(factory).inTests();
That's a lot closer to the way we speak.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@serhii-lekariev please see my comments.
public class EnvironmentDependantValue<P> { | ||
|
||
private @Nullable P productionValue; | ||
private final UnaryOperator<P> productionWrappingFunction; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this resolved?
@@ -313,11 +326,17 @@ public void close() throws Exception { | |||
if (tracerFactory != null) { | |||
tracerFactory.close(); | |||
} | |||
if (transportFactory != null) { | |||
transportFactory.close(); | |||
if (transportFactories.production() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To elimitate the repeating if (... .production().isPresent()) { ...}
please introduce the corresponding API to the EnvironmentDependantValue
itself.
I can see at least four cases only in this class.
server/src/main/java/io/spine/server/EnvironmentDependantValue.java
Outdated
Show resolved
Hide resolved
server/src/main/java/io/spine/server/EnvironmentDependantValue.java
Outdated
Show resolved
Hide resolved
…ances if possible. Add a hint to Javadocs. Partly convert the tests to a `Class<? extends EnvironmentType>` API.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@serhii-lekariev please see my comments.
* <p>For example: | ||
* <pre> | ||
* | ||
* {@literal EnvSetting <StorageFactory>} storageFactory = new EnvSetting<>(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's kill that extra space character.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The extra symbol is still there.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Try to generate Javadocs themselves. Let's see if new EnvSetting<>();
portion renders as expected.
} | ||
|
||
/** | ||
* Represents an operation over a value that returns no result and may finish with an error. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This name is way too generic for this particular case. That's why I proposed to name it more specifically.
* | ||
* <p>If it is not set, runs the specified supplier, configures and returns the supplied value. | ||
*/ | ||
V assignOrDefault(Supplier<V> defaultValue, EnvironmentType type) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now:
private final EnvSetting<MyFactory> setting = new EnvSetting<>();
//...
return setting.assignOrDefault( // this method says it writes, but in fact it reads — and sometimes writes.
() -> create();
type;
);
Proposed change:
private final EnvSetting<MyFactory> setting =
new EnvSetting<>(type, () -> create()); // default `fallback` value for `type`.
private final EnvSetting<AnotherFactory> anotherSetting = new EnvSetting<>(); // no fallbacks.
//...
MyFactory value = setting.value(); // mandatory setting, e.g. `StorageFactory`; throws ISE if `empty()`.
Optional<AnotherFactory> optionalValue = anotherSetting.optionalValue(); // optional setting, e.g. `Tracer`.
mention it in docs, clean up `ServerEnvironment`.
@armiol, PTAL again. Build fails because this branch depends on the |
* <p>For example: | ||
* <pre> | ||
* | ||
* {@literal EnvSetting <StorageFactory>} storageFactory = new EnvSetting<>(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The extra symbol is still there.
* <p>For example: | ||
* <pre> | ||
* | ||
* {@literal EnvSetting <StorageFactory>} storageFactory = new EnvSetting<>(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Try to generate Javadocs themselves. Let's see if new EnvSetting<>();
portion renders as expected.
* the type of value | ||
*/ | ||
@Internal | ||
public final class EnvSetting<V> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't understand why this class is public.
@@ -334,6 +338,10 @@ public static Delivery local() { | |||
* <p>The returned instance of {@code Delivery} is configured to use | |||
* {@linkplain UniformAcrossAllShards#singleShard() the single shard}. | |||
* | |||
* <p>To construct a {@code Delivery} instance, a {@code StorageFactory} is needed. | |||
* If it was not configured in the {@code ServerEnvironment}, uses a new {@code |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Who uses?
@@ -221,6 +225,9 @@ public DeliveryBuilder setInboxStorage(InboxStorage inboxStorage) { | |||
* | |||
* <p>If none set, the storage is initialized by the {@code StorageFactory} specific for | |||
* this {@code ServerEnvironment}. | |||
* | |||
* <p>If no {@code StorageFactory} is present in the {@code ServerEnvironment}, a new | |||
* {@code InMemoryStorage} is used. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is no such thing as InMemoryStorage
. Please review your changeset for this copy-paste mistake.
.isInstanceOf(SystemAwareStorageFactory.class); | ||
assertThat(((SystemAwareStorageFactory) serverEnvironment.storageFactory()).delegate()) | ||
.isSameInstanceAs(storageFactory); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please kill this line.
void reset() { | ||
serverEnvironment.reset(); | ||
Environment.instance() | ||
.register(new Local()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure if this piece is migrated to the latest base
API yet, but you may easily use a ctor instead of a new instance here.
Environment.instance() | ||
.register(new Local()); | ||
Environment.instance() | ||
.setTo(new Local()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See how weird this is? You have several pieces of the same inconvenient code in this test. How much easier that would be if you could treat setTo
as registration as well?
version.gradle.kts
Outdated
@@ -25,6 +25,6 @@ | |||
* as we want to manage the versions in a single source. | |||
*/ | |||
|
|||
val spineBaseVersion: String by extra("1.5.12") | |||
val spineBaseVersion: String by extra("1.5.18") | |||
val spineTimeVersion: String by extra("1.5.12") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's migrate to the latest time
once it's published.
Also, let's set the core-java
version to be the same as base
.
@armiol, PTAL again. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@serhii-lekariev LGTM in general. Please see my comments. Also, make sure to use the latest base
and time
versions before this PR is merged.
@@ -47,6 +47,29 @@ | |||
|
|||
/** | |||
* The server conditions and configuration under which the application operates. | |||
* | |||
* <h1>Configuration</h1> | |||
* <p>Some parts of the {@code ServerEnvironment} can be customized based on the {@code |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please have an empty line above.
* .use(testingStorageFactory, Tests.class) | ||
* .use(memoizingTracerFactory, Production.class) | ||
* </pre> | ||
* A custom environment type may also be used: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add <p>
and one more empty line above.
* // if `Staging` expects dependencies to its constructor. | ||
* ServerEnvironment.use(inMemoryStorageFactory, Staging.class); | ||
* </pre> | ||
* If {@code Staging} is {@link Environment#type() enabled}, the specified value is going to be |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Start with <p>
and add an empty line above.
* <p>Some parts of the {@code ServerEnvironment} can be customized based on the {@code | ||
* EnvironmentType}. To do so, one of the overloads of the {@code use} method can be called. | ||
* Two environment types exist out of the box: {@link Tests} and {@link Production}. For example: | ||
* <pre> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's have an empty line above.
* | ||
* <pre> | ||
* // This `Supplier` is calculated only once. | ||
* {@literal Supplier<StorageFactory>} fallbackStorage = InMemoryStorageFactory::newInstance; | ||
* | ||
* {@literal EnvSetting<StorageFactory>} setting = {@literal new EnvSetting<>(Tests.class, fallbackStorage);} | ||
* {@literal EnvSetting<StorageFactory>} setting = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we fit this into a single literal and in a single line?
{@literal EnvSetting<StorageFactory> setting = new EnvSetting<>(Tests.class, fallbackStorage);}
@serhii-lekariev so |
I've updated the PR description. |
EnvSetting
This PR introduces a new class for values that may differ between environments -
EnvSetting<P>
, which allows users to configure their value so that it's different between environments like so:ServerEnvironment
changesPreviously,
ServerEnvironment
allowed to use differentStorageFactory
instances for different environments.This functionality has been expanded to also allow configuration of:
Delivery
: defaults toDelivery.local()
if no value has been configured;TracerFactory
: does not default to any value, it's accessor still returns anOptional<TracerFactory>
;TransportFactory
: defaults to anInMemoryTransportFactory
for tests, still requires explicit configuration for all other environments.Deprecation notes
The following
ServerEnvironment
methods have been deprecated:configureStorageForTests
: preferuse(storage, Tests.class)
;configureStorage
: preferuse(storage, Production.class); // or any other env type
;configureDelivery
: preferuse(delivery, Production.class); // or any other env type
.Removed methods
ServerEnvironment#configureTransport(TransportFactory)
was removed.ServerEnvironment#use(TransportFactory, Class<? extends EnvironmentType)
can be used instead.Fixes #615.