-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #8 from dvgica/better-interface
Better interface
- Loading branch information
Showing
18 changed files
with
636 additions
and
524 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
74 changes: 0 additions & 74 deletions
74
periodic-api/src/main/scala/ca/dvgi/periodic/AutoUpdatingVar.scala
This file was deleted.
Oops, something went wrong.
File renamed without changes.
34 changes: 34 additions & 0 deletions
34
periodic-core/src/main/scala/ca/dvgi/periodic/AutoUpdater.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
package ca.dvgi.periodic | ||
|
||
import org.slf4j.Logger | ||
|
||
/** AutoUpdatingVar delegates most functionality to an AutoUpdater, which may have many | ||
* implementations. | ||
*/ | ||
trait AutoUpdater[U[_], R[_], T] extends AutoCloseable { | ||
|
||
/** Initializes the var for the first time, handling errors as specified. If successful, schedules | ||
* the next update. | ||
* | ||
* @param log | ||
* Implementations should use this logger for consistency. | ||
* | ||
* @return | ||
* An effect, which, if successfully completed, signifies that a value is available. If | ||
* initialization failed, the effect should also be failed. | ||
*/ | ||
def start( | ||
log: Logger, | ||
updateVar: () => U[T], | ||
updateInterval: UpdateInterval[T], | ||
updateAttemptStrategy: UpdateAttemptStrategy, | ||
handleInitializationError: PartialFunction[Throwable, U[T]] | ||
): R[Unit] | ||
|
||
/** The latest in-memory value of the variable. | ||
* | ||
* @return | ||
* Some[T] if the variable has been initialized successfully, otherwise None. | ||
*/ | ||
def latest: Option[T] | ||
} |
134 changes: 134 additions & 0 deletions
134
periodic-core/src/main/scala/ca/dvgi/periodic/AutoUpdatingVar.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
package ca.dvgi.periodic | ||
|
||
import scala.reflect.ClassTag | ||
import org.slf4j.LoggerFactory | ||
import ca.dvgi.periodic.jdk.Identity | ||
import ca.dvgi.periodic.jdk.JdkAutoUpdater | ||
import scala.concurrent.duration.Duration | ||
import scala.concurrent.Future | ||
import java.util.concurrent.ScheduledExecutorService | ||
|
||
/** A variable that updates itself. `latest` can be called from multiple threads, which are all | ||
* guaranteed to get the latest var. | ||
* | ||
* An AutoUpdatingVar attempts to get the variable immediately upon class instantiation. If this | ||
* fails, there are no further attempts (unless specified via `handleInitializationError`), and the | ||
* effect returned by the `ready` method will complete unsuccesfully. If it succeeds, the effect | ||
* completes successfully and `latest` can be safely called. | ||
* | ||
* Failed updates other than the first (those that throw an exception) may be retried with various | ||
* configurations. | ||
* | ||
* A successful update schedules the next update, with an interval that can vary based on the | ||
* just-updated var. | ||
* | ||
* @param updateVar | ||
* A thunk to initialize and update the var | ||
* @param updateInterval | ||
* Configuration for the update interval | ||
* @param updateAttemptStrategy | ||
* Configuration for retrying updates on failure | ||
* @param handleInitializationError | ||
* A PartialFunction used to recover from exceptions in the var initialization. If unspecified, | ||
* the exception will fail the effect returned by `ready`. | ||
* @param varNameOverride | ||
* A name for this variable, used in logging. If unspecified, the simple class name of T will be | ||
* used. | ||
*/ | ||
class AutoUpdatingVar[U[_], R[_], T](autoUpdater: AutoUpdater[U, R, T])( | ||
updateVar: => U[T], | ||
updateInterval: UpdateInterval[T], | ||
updateAttemptStrategy: UpdateAttemptStrategy, | ||
handleInitializationError: PartialFunction[Throwable, U[T]] = PartialFunction.empty, | ||
varNameOverride: Option[String] = None | ||
)(implicit ct: ClassTag[T]) | ||
extends AutoCloseable { | ||
|
||
private val varName = varNameOverride match { | ||
case Some(n) => n | ||
case None => ct.runtimeClass.getSimpleName | ||
} | ||
|
||
private val log = LoggerFactory.getLogger(s"AutoUpdatingVar[$varName]") | ||
|
||
log.info(s"Starting. ${updateAttemptStrategy.description}") | ||
|
||
private val _ready = autoUpdater.start( | ||
log, | ||
() => updateVar, | ||
updateInterval, | ||
updateAttemptStrategy, | ||
handleInitializationError | ||
) | ||
|
||
/** @return | ||
* An effect which, once successfully completed, signifies that the AutoUpdatingVar has a | ||
* value, i.e. `latest` can be called and no exception will be thrown. | ||
*/ | ||
def ready: R[Unit] = _ready | ||
|
||
/** Get the latest variable value from memory. Does not attempt to update the var. | ||
* | ||
* Wait for `ready` to be completed before calling this method. | ||
* | ||
* @return | ||
* The latest value of the variable. Calling this method is thread-safe. | ||
* @throws UnreadyAutoUpdatingVarException | ||
* if there is not yet a value to return | ||
*/ | ||
def latest: T = autoUpdater.latest.getOrElse(throw UnreadyAutoUpdatingVarException) | ||
|
||
override def close(): Unit = { | ||
autoUpdater.close() | ||
log.info(s"Shut down sucessfully") | ||
} | ||
} | ||
|
||
object AutoUpdatingVar { | ||
|
||
/** @see | ||
* [[ca.dvgi.periodic.AutoUpdatingVar]] | ||
*/ | ||
def apply[U[_], R[_], T](autoUpdater: AutoUpdater[U, R, T])( | ||
updateVar: => U[T], | ||
updateInterval: UpdateInterval[T], | ||
updateAttemptStrategy: UpdateAttemptStrategy, | ||
handleInitializationError: PartialFunction[Throwable, U[T]] = PartialFunction.empty, | ||
varNameOverride: Option[String] = None | ||
)(implicit ct: ClassTag[T]): AutoUpdatingVar[U, R, T] = { | ||
new AutoUpdatingVar(autoUpdater)( | ||
updateVar, | ||
updateInterval, | ||
updateAttemptStrategy, | ||
handleInitializationError, | ||
varNameOverride | ||
) | ||
} | ||
|
||
/** An AutoUpdatingVar based on only the JDK. | ||
* | ||
* @see | ||
* [[ca.dvgi.periodic.jdk.JdkAutoUpdater]] | ||
* @see | ||
* [[ca.dvgi.periodic.AutoUpdatingVar]] | ||
*/ | ||
def jdk[T]( | ||
updateVar: => T, | ||
updateInterval: UpdateInterval[T], | ||
updateAttemptStrategy: UpdateAttemptStrategy, | ||
handleInitializationError: PartialFunction[Throwable, T] = PartialFunction.empty, | ||
varNameOverride: Option[String] = None, | ||
blockUntilReadyTimeout: Option[Duration] = None, | ||
executorOverride: Option[ScheduledExecutorService] = None | ||
)(implicit ct: ClassTag[T]): AutoUpdatingVar[Identity, Future, T] = { | ||
new AutoUpdatingVar( | ||
new JdkAutoUpdater[T](blockUntilReadyTimeout, executorOverride) | ||
)( | ||
updateVar, | ||
updateInterval, | ||
updateAttemptStrategy, | ||
handleInitializationError, | ||
varNameOverride | ||
) | ||
} | ||
} |
File renamed without changes.
12 changes: 5 additions & 7 deletions
12
...dic/UpdateAttemptExhaustionBehavior.scala → ...dic/UpdateAttemptExhaustionBehavior.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
File renamed without changes.
Oops, something went wrong.