Scala polling loop without vars - scala

What's the Scala best-practice for polling and API?
I'm trying to write a Scala method that polls an API, checking if it reached "SUCCESS". While polling, it also might reach bad stated like "FAILED" or "TIMEOUT".
In Java, I'd write something like:
public String pollEndpoint() {
boolean isPolling = true;
String result = "NA";
while (isPolling) {
Response response = getResponse("http://myAPI.com/ready?id=1234");
if (response.status == "FAILED") { throw new FailedException(response.reason);}
else ... //Some other bad conditions
else if (response.status == "SUCCESS") {
isPolling = false;
result = response.result;
}
System.out.println("Current state is " + response.status); // When running, will be "RUNNING"
Thread.sleep(1000);
}
}
In Scala I can do:
def pollEndpoint():String = {
var isPolling = true
var result = "NA"
while (isPolling) {
val response = getResponse("http://myAPI.com/ready?id=1234")
if (response.status == "FAILED") { throw new FailedException(response.reason)}
else ... //Some other bad conditions
else if (response.status == "SUCCESS") {
isPolling = false
result = response.result
}
println("Current state is " + response.status); // When running, will be "RUNNING"
Thread.sleep(1000)
}
}
But this solution uses vars.
Is there any nice way of doing this, using only vals?

As Luis mentioned in comment, you can just write a recursive for that:
def pollEndpoint():String = {
val response = getResponse("http://myAPI.com/ready?id=1234")
println("Current state is " + response.status); // When running, will be "RUNNING"
if (response.status == "FAILED") { ??? }
else if (response.status == "SUCCESS") {
response.result
} else {
Thread.sleep(1000)
pollEndpoint()
}
}
The following will mock getResponse:
var i = 5
def getResponse(str: String): Response = {
if (i < 0) {
Response("SUCCESS", "Great success")
} else {
i = i - 1
Response("Wait", "Not done yet.")
}
}
And the call:
pollEndpoint()
Will produce:
Current state is Wait
Current state is Wait
Current state is Wait
Current state is Wait
Current state is Wait
Current state is Wait
Current state is SUCCESS
Having said all of that, it is way better instead of defining getResponse as it is, we might do:
def getResponse(str: String): Future[Response]
And then simply:
getResponse("http://myAPI.com/ready?id=1234").map { response =>
// Handle response
}

It depends on what information determines the repetition (i.e. when to loop) and what information is returned to the outside world, but under the right circumstances you might iterate() instead of looping or recursing.
def pollEndpoint():String = {
Iterator.iterate(getResponse("<yadda-yadda>")){ response =>
response.status match {
case "FAILED" => //log error, throw exception, etc.
case stat => //log whatever
Thread.sleep(1000)
}
getResponse("<yadda-yadda>")
}.dropWhile(_.status != "SUCCESS") //test for exit condition/s
.next().result
}

Related

Using Post Request return a multiple values in Unity

I am new to Unity i have created a Post Request from that i want to return the Authentication-Token Header and authorization header and some required json data here is my code
private IEnumerator BasketId()
{
string url = "http://hololens5.northeurope.cloudapp.azure.com/INTERSHOP/rest/WFS/inSPIRED-inTRONICS-Site/-/baskets/";
using (UnityWebRequest request = UnityWebRequest.Post(url, "Hello"))
{
yield return request.SendWebRequest();
string token = request.GetResponseHeader("Authentication-token");
if (request.isNetworkError || request.isHttpError)
{
Debug.Log(request.error);
}
else
{
string jsonResut = System.Text.Encoding.UTF8.GetString(request.downloadHandler.data);
obj = JsonConvert.DeserializeObject<BasketId>(jsonResut);
Debug.Log(obj.Uri);
Debug.Log("Authentication-Token: " + token);
yield return obj.Title;
yield return token;
}
}
}
so i could i return the values. Please help me.
Because Coroutine is not immediate (blocking) so you won't be able to return the response directly. What you need to do is to have an event or callback that will be called when your request completed.
Here is how you can achieve it by passing the callback as argument:
private IEnumerator GetBasketId(System.Action<string, BasketId> callback)
{
string url = "http://hololens5.northeurope.cloudapp.azure.com/INTERSHOP/rest/WFS/inSPIRED-inTRONICS-Site/-/baskets/";
using (UnityWebRequest request = UnityWebRequest.Post(url, "Hello"))
{
yield return request.SendWebRequest();
if (request.isNetworkError || request.isHttpError)
{
Debug.Log(request.error);
if (callback != null)
{
callback(null, null);
}
// callback?.Invoke(null, null); // for short
}
else
{
if (callback != null)
{
string token = request.GetResponseHeader("Authentication-token");
string jsonResut = System.Text.Encoding.UTF8.GetString(request.downloadHandler.data);
obj = JsonConvert.DeserializeObject<BasketId>(jsonResut);
if (callback != null)
{
callback(token, obj);
}
// callback?.Invoke(token, obj); // for short
}
}
}
}
so when you want to start the request simply call something like:
StartCoroutine(GetBasketId((token, basketId) =>
{
if (string.IsNullOrEmpty(token))
{
// Handle error
}
else
{
// Handle success
Debug.Log("Token: " + token);
Debug.Log(basketId.Title);
}
});

How to pass a test if expect fails

I have this code
it('This should pass anyway', function (done) {
testObj.testIt(regStr);
});
testObj
this.testIt = function (regStr) {
selector.count().then(function (orgCount) {
for (var curr = 0; curr < count; curr++) {
checkField(curr, regStr);
}
});
};
function checkField(curr, regStr) {
selector.get(curr).all(by.tagName('li')).get(0).getInnerHtml().then(function (text) {
expect(text).to.match(regStr, curr + '#ERR');
});
}
If one of these expects get a failure, test fails. How can i handle this? I mean - can i somehow count passed and failed expect()ations and return it? or, at least, dont let test break on first error.
I've tried try-catch, but nothing good happened.
it('This should pass anyway', function (done) {
try {
testObj.testIt(regStr);
} catch (e) {
console.log('#err' + e);
}
});
And then i wanted to use done(), but havent found any examples to do the similar. Can u please help me?
Sry for my english
UPD
You can return either null or a string from checkField(), join them up, and expect the array to be empty:
this.testIt = function (regStr) {
selector.count().then(function (orgCount) {
var errors = [];
for (var curr = 0; curr < orgCount; curr++) {
var e = checkField(curr, regStr);
if (e) { errors.push(e); }
}
assert.equal(0, errors.length, errors);
});
};
A cleaner approach would be to use map() to collect the data into an array:
var data = selector.map(function (elm) {
return elm.element(by.tagName('li')).getText();
});
expect(data).toEqual(["test1", "test2", "test3"]);

return/break a function from the derived base class

In my REST API service layer, I have a class ProductService.
The following logic exists in all my functions: Do Validate, if validation fails i throw invalid exception, if passes, i continue to the next try-catch and throw general-error in case of failure:
def addProduct(request:AddProductRequest): BaseResponse[String] =
{
try
{
request.validate
}
catch
{
case ex: Exception => {
Logger.error("Failed to add product, Validation failed", ex);
val errorResponse:ErrorResponse[String] = new ErrorResponseList().InvalidParameters
errorResponse.addMessage(ex.getMessage)
return errorResponse
}
}
try
{
val addedProductId = productRepository.addProduct(request.language, request.tenantId, request.product)
DTOResponse(addedProductId)
}
catch
{
case ex: Exception => {
Logger.error("Failed to add product to tenant Id="+request.tenantId+" language="+request.language, ex);
val errorResponse:ErrorResponse[String] = new ErrorResponseList().GeneralError
errorResponse.addMessage(ex.getMessage())
return errorResponse
}
}
}
Now, instead of repeating the request.validate with the same try and catch for all functions, i created a base class with the following function:
abstract class ServiceBase {
def validate[T](request:BaseRequest)
{
try
{
request.validate
}
catch
{
case ex: Exception => {
Logger.error("Validation failed", ex);
val errorResponse:ErrorResponse[String] = new ErrorResponseList().InvalidParameters
errorResponse.addMessage(ex.getMessage)
return errorResponse
}
}
}
So now, my addProduct(..) will look like:
validate(request)
..the rest of the code - the 2nd try-catch
This saves alot of lines.
The problem is that if validation fails, it will never return. I get the following errors in ServiceBase:
Multiple markers at this line
- enclosing method validate has result type Unit: return value discarded
- enclosing method validate has result type Unit: return value discarded
- a pure expression does nothing in statement position; you may be omitting necessary
parentheses
validate has no return type (and thus defaults to returning Unit), in ServiceBase your signature for validate should look like this:
def validate[T](request:BaseRequest): BaseResponse[String] =
(assuming you want to return a BaseResponse[String])
this may be useful to someone, someday, functional programming.. Did we say ^_^
Changed the ServiceBase validate to:
def validate[T](request:BaseRequest):Option[BaseResponse[T]] =
{
try
{
request.validate
None
}
catch
{
case ex: Exception => {
Logger.error("Validation failed", ex);
val errorResponse:ErrorResponse[T] = new ErrorResponseList().InvalidParameters
errorResponse.addMessage(ex.getMessage)
return Some(errorResponse)
}
}
}
And now i do:
def getProducts(request:GetProductsRequest) :BaseResponse[ProductSearchResults] =
{
validate[ProductSearchResults](request).getOrElse(
{
try
{
val products = productRepository.getProducts(request.language,request.tenantId,request.productIds)
val foundProducts = for (product <- products) yield (product.id)
val notFoundProducts = request.productIds filterNot (foundProducts.toSet)
val responseWrapper = new ProductSearchResults(products, notFoundProducts)
DTOResponse(responseWrapper)
}
catch
{
case ex: Exception => {
Logger.error("Failed to get products from tenant Id="+request.tenantId+" language="+request.language, ex);
val errorResponse:ErrorResponse[ProductSearchResults] = new ErrorResponseList().GeneralError
errorResponse.addMessage(ex.getMessage())
return errorResponse
}
}})
}

Why scala does not finish function in Catch

I validate my function, if an exception is thrown during validation, i wish to stop the method in the catch and return, from some reason, it will continue and only caught in the main try /catch.
Code:
def updateProduct(request: UpdateProductRequest): BaseResponse[String] =
{
try
{
try
{
ValidateUpdateProductRequest(request)
}
catch
{
case ex: Exception => {
val errorResponse:ErrorResponse[String] = ErrorResponse(ErrorCode.InvalidParameters, ex.getMessage, 500)
errorResponse // <=- This does not return from function.. In debug i get here
}
}
val deleteProductResult = productRepository.updateProduct(request) //I dont want to get here !!
DTOResponse(deleteProductResult)
}
catch
{
case ex: Exception => {
Logger.error("Failed to update product Id = " +request.product.id, ex);
var errorResponse:ErrorResponse[String] = ErrorResponse(ErrorCode.GeneralError, ex.getMessage, 500)
errorResponse
}
}
}
I Understand in scala the last line of function is the only place function will return, so how do i return from the catch ?
The reason is i want to use different ErrorCode in the BaseResponse[string]
Thanks!
Whenever you have an inner expression that you want to propagate to the outermost level to be the result, you can either assign it to a temporary variable in an outer expression, or use return. So, for example:
def foo: Int = {
try { bar }
catch { case ikte: IKnowTheAnswerException => return 42 }
lotsOfMath
}
def foo: Int = {
val iKnowIt = {
try { bar }
catch { case ikte: IKnowTheAnswerException => Some(42) }
}
iKnowIt.getOrElse( lotsOfMath )
}
Even though the second pattern seems uselessly wordy, keep in mind that jumping out of the method with a return is not always obvious, especially in longer methods. So the second can, in some cases, be clearer to read (especially when you know to expect the pattern).

Subsequent Call to Actor Freezes Program

I put together the code below; the intent was to have a non-blocking server accept a connection and then pass off this connection to an actor for further processing. This works the first time through, but on the subsequent request the program freezes at conServ ! servSoc.accept. Any ideas why this is happening?
import java.net._
import java.io._
import java.nio._
import java.nio.channels._
import java.util._
import scala.actors.Actor
import scala.actors.Actor._
def test() = {
var channel: ServerSocketChannel = null
val isa: InetSocketAddress = new InetSocketAddress(23)
val conServ = actor {
react {
case conn: Socket => {
try {
var pw: PrintWriter = new PrintWriter(conn.getOutputStream(), true)
pw.println("Current time: " + new Date)
pw.close
conn.close
} catch {
case ioe: IOException => println("IOException: " + ioe.getMessage)
case e: Exception => println("Exception: " + e.getMessage)
}
}
}
}
try {
channel = ServerSocketChannel.open
channel.configureBlocking(false)
channel.socket().bind(isa)
var selector: Selector = Selector.open
channel.register(selector, SelectionKey.OP_ACCEPT)
println("** Server ready for requests **")
while (true) {
if (selector.select > 0) {
var selKeys: Set[SelectionKey] = selector.selectedKeys
var selIt: Iterator[SelectionKey] = selKeys.iterator
while (selIt.hasNext) {
var key: SelectionKey = selIt.next.asInstanceOf[SelectionKey]
selIt.remove
if (key.isAcceptable) {
var ssc: ServerSocketChannel = key.channel.asInstanceOf[ServerSocketChannel]
var servSoc: ServerSocket = ssc.socket
try {
conServ ! servSoc.accept
} catch {
case ioe: IOException => println(ioe.printStackTrace)
}
}
}
} else {
continue
}
}
} catch {
case ioe: IOException => println("Could not listen to port 23. " + ioe.printStackTrace)
case e: Exception => println("Error: " + e.printStackTrace)
}
}
test
Enclose your react in a loop block like this:
val conServ = actor {
loop {
react {
// ...
}
}
}
What happens now, is that your actor is started, processes the first message and is not "reacting" again to process additional message from its queue.
See An actor's act method that uses loop.
This is what an actor do, treating one message at the time. What you want is a separate thread to handle each request. For this you can try using Futures.