Play-ParSeq is a Play module which seamlessly integrates ParSeq with Play Framework.
ParSeq is a Java framework for writing async code, which has several advantages over Play F.Promise or Scala Future, e.g. ParSeq Trace for async code's runtime visualization, async code reuse via Task composition and taking control of async code's lifecycle.
Key features:
- Executes ParSeq
Task
and generates Java PlayF.Promise
or ScalaFuture
, which allows ParSeq Tasks to be used for executing Play Action. - Converts from Java
Callable<F.Promise<T>>
or Scala() => Future[T]
to ParSeqTask
, which allows existing code using Play native APIs to be integrated with ParSeq Tasks. - Supports ParSeq Trace.
- Provides both Scala and Java API.
- Requires Play 2.4 (Dependency Injection).
[TODO] Need to setup maven first.
-
Set the injected router for your build setting in your
build.sbt
.... routesGenerator := InjectedRoutesGenerator ...
-
Put the preset module
PlayParSeqModule
into yourapplication.conf
.... play.modules.enabled += "com.linkedin.playparseq.j.modules.PlayParSeqModule" ...
-
Inject
PlayParSeq
into your Controller.... private final PlayParSeq _playParSeq; @Inject public Sample(final PlayParSeq playParSeq) { this._playParSeq = playParSeq; ...
-
Use
PlayParSeq
in your Action.... public F.Promise<Result> demo() { // Convert to ParSeq Task Task<String> helloworldTask = _playParSeq.toTask("helloworld", () -> F.Promise.pure("Hello World")); // Run the Task return _playParSeq.runTask(helloworldTask) .map(Results::ok); } ...
-
Put additional preset module for
ParSeqTraceModule
into yourapplication.conf
.... play.modules.enabled += "com.linkedin.playparseq.trace.j.modules.ParSeqTraceModule" ...
-
Put ParSeq Trace resource route into your
routes
.... -> / com.linkedin.playparseq.trace.Routes ...
-
Annotate your Action by putting
@With(ParSeqTraceAction.class)
.... @With(ParSeqTraceAction.class) public F.Promise<Result> demo() { ...
-
Access
[original-route]?parseq-trace=true
will display ParSeq Trace Viewer for your original request if your application is indev
mode.
-
Set the injected router for your build setting in your
build.sbt
.... routesGenerator := InjectedRoutesGenerator ...
-
Put the preset module
PlayParSeqModule
into yourapplication.conf
.... play.modules.enabled += "com.linkedin.playparseq.s.modules.PlayParSeqModule" ...
-
Inject
PlayParSeq
into your Controller.... class Sample @Inject()(playParSeq: PlayParSeq) extends Controller { ...
-
Use
PlayParSeq
in your Action.... def demo = Action.async(implicit request => { // Convert to ParSeq Task val helloworldTask = playParSeq.toTask("helloworld", () => Future("Hello World")) // Run the Task playParSeq.runTask(helloworldTask) .map(Ok(_)) }) ...
-
Put additional preset module for
ParSeqTraceModule
into yourapplication.conf
.... play.modules.enabled += "com.linkedin.playparseq.trace.s.modules.ParSeqTraceModule" ...
-
Put ParSeq Trace resource route into your
routes
.... -> / com.linkedin.playparseq.trace.Routes ...
-
Inject
ParSeqTraceAction
into your Controller.... class Sample @Inject()(playParSeq: PlayParSeq, parSeqTraceAction: ParSeqTraceAction) extends Controller { ...
-
Use
parSeqTraceAction.async
for your Action.... def demo = parSeqTraceAction.async(implicit request => { ...
-
Access
[original-route]?parseq-trace=true
will display ParSeq Trace Viewer for your original request if your application is indev
mode.
Please see /sample
.
A: Please first make sure you annotated your Action with @With(ParSeqTraceAction.class)
in Java, or you used parSeqTraceAction.async
for your Action in Scala. Then check whether you meet all ParSeqTraceSensor
requirements of showing ParSeq Trace. And also don't forget using runTask
in your Action.
A: If you don't want to use the preset modules, please write your own Module and register it by putting into your application.conf
. Almost every part of Play-ParSeq follows the DI, so you can easily replace any part with your own.
A: Yes. If you don't want to use the default value, please insert the corresponding settings into your application.conf
.
Name | Description | Default |
---|---|---|
parseq.engine.numThreads | The number of threads in Engine's pool. | Available processors + 1 |
parseq.engine.terminationWaitSeconds | The maximum time to wait for Engine's termination in the unit of seconds. | 1 |
parseq.trace.docLocation | The file path of the dot, which is part of graphviz for generating Task's graphviz view. | Registered location if installed |
parseq.trace.cacheSize | The number of cache items in GraphvizEngine. | 1024 |
parseq.trace.getTimeoutMilliseconds | The timeout of the GraphvizEngine execution in the unit of milliseconds. | 5000 |
parseq.trace.parallelLevel | The maximum of the GraphvizEngine's parallel level. | 1 |
parseq.trace.delayMilliseconds | The delay time between different executions of the GraphvizEngine in the unit of milliseconds. | 5 |
parseq.trace.processQueueSize | The size of the GraphvizEngine's process queue. | 1000 |
A: Yes. Play-ParSeq supports this. However, you shouldn't be running multiple Tasks, otherwise the order of execution might not be accurate, which minimizes the benefits of ParSeq.
A: Yes.
A: You can follow the instructions below:
-
Implements
ParSeqTraceSensor
with your own requirements.... // Java @Singleton public class MySensorImpl implements ParSeqTraceSensor { @Override public boolean isEnabled(Http.Context ctx, ParSeqTaskStore parSeqTaskStore) { return [your-requirements]; } } ...
... // Scala @Singleton class MySensorImpl extends ParSeqTraceSensor { override def isEnabled(requestHeader: RequestHeader, parSeqTaskStore: ParSeqTaskStore): Boolean = [your-requirements] } ...
-
Create your own Module to include the binding of your
ParSeqTraceSensor
.... // Java public class MyModule extends Module { @Override public Seq<Binding<?>> bindings(final Environment environment, final Configuration configuration) { return seq( bind(ParSeqTraceSensor.class).to(MySensorImpl.class), [other-bindings]); } } ...
... // Scala class MyModule extends Module { override def bindings(environment: Environment, configuration: Configuration): Seq[Binding[_]] = Seq( bind[ParSeqTraceSensor].to[MySensorImpl], [other-bindings]) } ...
-
Register your Module in your
application.conf
.... play.modules.enabled += [package-of-MyModule] ...
-
Have two ice-creams.
A: It's not possible with the current ParSeqTaskStore implementation, which is based on Play Framework's Java or Scala specific request APIs. Play 3.0 will hopefully provide a common underlying request which will remove this limitation. However, you can inject your own implementation of ParSeqTaskStore, such as shared cache or local file, to make this happen.
Copyright 2015 LinkedIn Corp.
Licensed under the Apache License, Version 2.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.