PutIfExists fails if a record has been recently added - scalardb

In ScalarDB, the library that add ACID functionality to Cassandra, I am getting the following error
2020-09-24 18:51:33,607 [WARN] from com.scalar.db.transaction.consensuscommit.CommitHandler in ScalaTest-run-running-AllRepositorySpecs - preparing records failed
com.scalar.db.exception.storage.NoMutationException: no mutation was applied.
I am running a test case in which I get a record to check that it doesn't exist, then I add the record, then I fetch it to see it was successfully added, then I update it and then I get it again to see that the value was updated.
"update an answer if the answer exists" in {
beforeEach()
embeddedCassandraManager.executeStatements(cqlStartupStatements)
val cassandraConnectionService = CassandraConnectionManagementService()
val (cassandraSession, cluster) = cassandraConnectionService.connectWithCassandra("cassandra://localhost:9042/codingjedi", "codingJediCluster")
//TODOM - pick the database and keyspace names from config file.
cassandraConnectionService.initKeySpace(cassandraSession.get, "codingjedi")
val transactionService = cassandraConnectionService.connectWithCassandraWithTransactionSupport("localhost", "9042", "codingJediCluster" /*,dbUsername,dbPassword*/)
val repository = new AnswersTransactionRepository("codingjedi", "answer_by_user_id_and_question_id")
val answerKey = AnswerKeys(repoTestEnv.answerTestEnv.answerOfAPracticeQuestion.answer_id.get,
repoTestEnv.answerTestEnv.answerOfAPracticeQuestion.question_id,
Some(repoTestEnv.answerTestEnv.answerOfAPracticeQuestion.answer_id.get))
logger.trace(s"checking if answer already exists")
val distributedTransactionBefore = transactionService.get.start()
val resultBefore = repository.get(distributedTransactionBefore, answerKey) //answer should not exist
distributedTransactionBefore.commit()
resultBefore.isLeft mustBe true
resultBefore.left.get.isInstanceOf[AnswerNotFoundException] mustBe true
logger.trace(s"no answer found. adding answer")
val distributedTransactionDuring = transactionService.get.start()
repository.add(distributedTransactionDuring, repoTestEnv.answerTestEnv.answerOfAPracticeQuestion)//add answer
distributedTransactionDuring.commit()
logger.trace(s"answer added")
val distributedTransactionAfter = transactionService.get.start()
val result = repository.get(distributedTransactionAfter, answerKey) //now answer should exist
distributedTransactionAfter.commit()
result mustBe (Right(repoTestEnv.answerTestEnv.answerOfAPracticeQuestion))
logger.trace(s"got answer from repo ${result}")
val updatedNotes = if(repoTestEnv.answerTestEnv.answerOfAPracticeQuestion.notes.isDefined)
Some(repoTestEnv.answerTestEnv.answerOfAPracticeQuestion.notes.get+"updated") else Some("updated notes")
val updatedAnswer = repoTestEnv.answerTestEnv.answerOfAPracticeQuestion.copy(notes=updatedNotes) //updated answer
logger.trace(s"old notes ${repoTestEnv.answerTestEnv.answerOfAPracticeQuestion.notes} vs new notes ${updatedNotes}")
logger.trace(s"updated answer ${updatedAnswer}")
val distributedTransactionForUpdate = transactionService.get.start()
val resultOfupdate = repository.update(distributedTransactionForUpdate,updatedAnswer) //update answer
distributedTransactionForUpdate.commit() //fails here
logger.trace(s"update done. getting answer again")
val distributedTransactionAfterUpdate = transactionService.get.start()
val resultAfterUpdate = repository.get(distributedTransactionAfterUpdate, answerKey)
distributedTransactionForUpdate.commit()
resultAfterUpdate mustBe (Right(updatedAnswer))
logger.trace(s"got result after update ${resultAfterUpdate}")
afterEach()
}
The update method calls add with putIfExists condition
def update(transaction:DistributedTransaction, answer:AnswerOfAPracticeQuestion) = {
logger.trace(s"updating answer value ${answer}")
//checktest-update an answer if the answer exists
add(transaction,answer, new PutIfExists)
}
def add(transaction:DistributedTransaction,answer:AnswerOfAPracticeQuestion,mutationCondition:MutationCondition = new PutIfNotExists()) = {
logger.trace(s"adding answer ${answer} with mutation state ${mutationCondition}")
val pAnswerKey = new Key(new TextValue("answered_by_user", answer.answeredBy.get.answerer_id.toString),
new TextValue("question_id",answer.question_id.toString))
//to check duplication, both partition and clustering keys need to be present
//val cAnswerKey = new Key(new TextValue("answer_id",answer.answer_id.toString))
//logger.trace(s"created keys. ${pAnswerKey}, ${cAnswerKey}")
val imageData = answer.image.map(imageList=>imageList).getOrElse(List())
logger.trace(s"will check in ${keyspaceName},${tablename}")
val putAnswer: Put = new Put(pAnswerKey/*,cAnswerKey*/)
.forNamespace(keyspaceName)
.forTable(tablename)
.withCondition(mutationCondition)
.withValue(new TextValue("answer_id", answer.answer_id.get.toString))
.withValue(new TextValue("image", convertImageToString(imageData)))
.withValue(new TextValue("answer", convertAnswersFromModelToString(answer.answer)))
.withValue(new BigIntValue("creation_year", answer.creationYear.getOrElse(0)))
.withValue(new BigIntValue("creation_month", answer.creationMonth.getOrElse(0)))
.withValue(new TextValue("notes", answer.notes.getOrElse("")))
logger.trace(s"putting answer ${putAnswer}")
//checktest-add answer to respository
//checktest-not add answer to respository if duplicate
transaction.put(putAnswer)
}
Why am I getting the error even though the notes field is changed between the existing answer and the updated answer
The error trace is (note that it says IF NOT EXISTS!). Shouldn't it be IF EXISTS? There is also a trace there was a hit in the statement cache for [INSERT INTO codingjedi.answer_by_user_id_and_question_id (answered_by_user,question_id,tx_id,tx_state,tx_prepared_at,answer_id,image,answer,creation_year,creation_month,notes,tx_version) VALUES (?,?,?,?,?,?,?,?,?,?,?,?) IF NOT EXISTS;]. Does it mean that the previous put is still in cache and is that causing the conflict?
2020-09-24 18:51:33,593 [DEBUG] from com.scalar.db.storage.cassandra.StatementHandler in ScalaTest-run-running-AllRepositorySpecs - query to prepare : [INSERT INTO codingjedi.answer_by_user_id_and_question_id (answered_by_user,question_id,tx_id,tx_state,tx_prepared_at,answer_id,image,answer,creation_year,creation_month,notes,tx_version) VALUES (?,?,?,?,?,?,?,?,?,?,?,?) IF NOT EXISTS;].
2020-09-24 18:51:33,593 [DEBUG] from com.scalar.db.storage.cassandra.StatementHandler in ScalaTest-run-running-AllRepositorySpecs - there was a hit in the statement cache for [INSERT INTO codingjedi.answer_by_user_id_and_question_id (answered_by_user,question_id,tx_id,tx_state,tx_prepared_at,answer_id,image,answer,creation_year,creation_month,notes,tx_version) VALUES (?,?,?,?,?,?,?,?,?,?,?,?) IF NOT EXISTS;].
2020-09-24 18:51:33,593 [DEBUG] from com.scalar.db.storage.cassandra.ValueBinder in ScalaTest-run-running-AllRepositorySpecs - Optional[11111111-1111-1111-1111-111111111111] is bound to 0
2020-09-24 18:51:33,593 [DEBUG] from com.scalar.db.storage.cassandra.ValueBinder in ScalaTest-run-running-AllRepositorySpecs - Optional[11111111-1111-1111-1111-111111111111] is bound to 1
2020-09-24 18:51:33,593 [DEBUG] from com.scalar.db.storage.cassandra.ValueBinder in ScalaTest-run-running-AllRepositorySpecs - Optional[468492df-0960-4160-8391-27fe7fa626c5] is bound to 2
2020-09-24 18:51:33,593 [DEBUG] from com.scalar.db.storage.cassandra.ValueBinder in ScalaTest-run-running-AllRepositorySpecs - 1 is bound to 3
2020-09-24 18:51:33,593 [DEBUG] from com.scalar.db.storage.cassandra.ValueBinder in ScalaTest-run-running-AllRepositorySpecs - 1600969893592 is bound to 4
2020-09-24 18:51:33,593 [DEBUG] from com.scalar.db.storage.cassandra.ValueBinder in ScalaTest-run-running-AllRepositorySpecs - Optional[11111111-1111-1111-1111-111111111111] is bound to 5
2020-09-24 18:51:33,593 [DEBUG] from com.scalar.db.storage.cassandra.ValueBinder in ScalaTest-run-running-AllRepositorySpecs - Optional[{"image":["image1binarydata","image2binarydata"]}] is bound to 6
2020-09-24 18:51:33,593 [DEBUG] from com.scalar.db.storage.cassandra.ValueBinder in ScalaTest-run-running-AllRepositorySpecs - Optional[{"answer":[{"filename":"c.js","answer":"some answer"}]}] is bound to 7
2020-09-24 18:51:33,593 [DEBUG] from com.scalar.db.storage.cassandra.ValueBinder in ScalaTest-run-running-AllRepositorySpecs - 2019 is bound to 8
2020-09-24 18:51:33,593 [DEBUG] from com.scalar.db.storage.cassandra.ValueBinder in ScalaTest-run-running-AllRepositorySpecs - 12 is bound to 9
2020-09-24 18:51:33,593 [DEBUG] from com.scalar.db.storage.cassandra.ValueBinder in ScalaTest-run-running-AllRepositorySpecs - Optional[some notesupdated] is bound to 10
2020-09-24 18:51:33,593 [DEBUG] from com.scalar.db.storage.cassandra.ValueBinder in ScalaTest-run-running-AllRepositorySpecs - 1 is bound to 11
2020-09-24 18:51:33,607 [WARN] from com.scalar.db.transaction.consensuscommit.CommitHandler in ScalaTest-run-running-AllRepositorySpecs - preparing records failed
com.scalar.db.exception.storage.NoMutationException: no mutation was applied.
UPDATE
Traces
For the 1st put, putAnswer is
putting answer Put{namespace=Optional[codingjedi], table=Optional[answer_by_user_id_and_question_id], partitionKey=Key{TextValue{name=answered_by_user, value=Optional[11111111-1111-1111-1111-111111111111]}, TextValue{name=question_id, value=Optional[11111111-1111-1111-1111-111111111111]}}, clusteringKey=Optional.empty, values={answer_id=TextValue{na
me=answer_id, value=Optional[11111111-1111-1111-1111-111111111111]}, image=TextValue{name=image, value=Optional[{"image":["image1binarydata","image2binarydata"]}]}, answer=TextValue{name=answer, value=Optional[{"answer":[{"filename":"c.j
s","answer":"some answer"}]}]}, creation_year=BigIntValue{name=creation_year, value=2019}, creation_month=BigIntValue{name=creation_month, value=12}, notes=TextValue{name=notes, value=Optional[some notes]}}, consistency=SEQUENTIAL, condi
tion=Optional[com.scalar.db.api.PutIfNotExists#21bf308]}
For the 2nd put, putAnswer is
putting answer Put{namespace=Optional[codingjedi], table=Optional[answer_by_user_id_and_question_id], partitionKey=Key{TextValue{name=answered_by_user, value=Optional[11111111-1111-1111-1111-111111111111]}, TextValue{name=question_id, value=Optional[11111111-1111-1111-1111-111111111111]}}, clusteringKey=Optional.empty, values={answer_id=TextValue{name=answer_id, value=Optional[11111111-1111-1111-1111-111111111111]}, image=TextValue{name=image, value=Optional[{"image":["image1binarydata","image2binarydata"]}]}, answer=TextValue{name=answer, value=Optional[{"answer":[{"filename":"c.js","answer":"some answer"}]}]}, creation_year=BigIntValue{name=creation_year, value=2019}, creation_month=BigIntValue{name=creation_month, value=12}, notes=TextValue{name=notes, value=Optional[some notesupdated]}}, consistency=SEQUENTIAL, condition=Optional[com.scalar.db.api.PutIfExists#2e057637]}
notes field has changed from notes=TextValue{name=notes, value=Optional[some notes]}}, to notes=TextValue{name=notes, value=Optional[some notesupdated]}}
When the 2nd put is executed, I can see that the mutation condition used is IfNotExists
2020-09-25 12:35:34,188 [DEBUG] from com.scalar.db.storage.cassandra.Cassandra in ScalaTest-run-running-AllRepositorySpecs - executing put operation with Put{namespace=Optional[codingjedi], table=Optional[answer_by_user_id_and_question_id], partitionKey=Key{TextValue{name=answered_by_user, value=Optional[11111111-1111-1111-1111-111111111111]}, TextValue{name=question_id, value=Optional[11111111-1111-1111-1111-111111111111]}}, clusteringKey=Optional.empty, values={tx_id=TextValue{name=tx_id, value=Optional[c6bc39e9-656a-440c-8f68-af6005f37f7c]}, tx_state=IntValue{name=tx_state, value=1}, tx_prepared_at=BigIntValue{name=tx_prepared_at, value=1601033734188}, answer_id=TextValue{name=answer_id, value=Optional[11111111-1111-1111-1111-111111111111]}, image=TextValue{name=image, value=Optional[{"image":["image1binarydata","image2binarydata"]}]}, answer=TextValue{name=answer, value=Optional[{"answer":[{"filename":"c.js","answer":"some answer"}]}]}, creation_year=BigIntValue{name=creation_year, value=2019}, creation_month=BigIntValue{name=creation_month, value=12}, notes=TextValue{name=notes, value=Optional[**some notesupdated**]}, tx_version=IntValue{name=tx_version, value=1}}, consistency=LINEARIZABLE, condition=Optional[com.scalar.db.api.**PutIfNotExists**#21bf308]}

Scalar DB doesn't allow a blind write for the existing record. It looks there is no get before the update.
I think this process should check the current values and update the values in a transaction. In this code, there is no guarantee for atomicity between the get and the update.

Since the protocol is based on Snapshot Isolation, it needs to get a record in a snapshot first to update the record.

After Yuji's comment below, I changed the update method to add a get before put and the operation is successful now.
def update(transaction:DistributedTransaction, answer:AnswerOfAPracticeQuestion) = {
logger.trace(s"updating answer value ${answer}")
val key = AnswerKeys(answer.answeredBy.get.answerer_id,answer.question_id,answer.answer_id)
val result = get(transaction,key)
if(result.isLeft) throw result.left.get else add(transaction,answer, new PutIfExists())
}
I however don't understand why a get is required before update or delete in Scalardb

Related

hashicorp vault agent template fails when starts with "no known secret ID"

Start vault agent using template:
vault agent -config=templates/config.hcl -log-level=debug
Fails with the following error:
[ERROR] auth.handler: error getting path or data from method: error="no known secret ID" backoff=2.438818298
Steps for reproduce the issue:
Policy:
path "my-app/data/testsecret/*" {
capabilities = ["create", "update", "read"]
}
path "my-app/metadata/testsecret/*" {
capabilities = ["list"]
}
Client config:
pid_file = "./pidfile"
vault {
address = "http://XX.XX.XX.XX:XXXX"
}
auto_auth {
method {
type = "approle"
config = {
role_id_file_path = "templates/roleid"
secret_id_file_path = "templates/secretid"
}
}
sink {
type = "file"
config = {
path = "templates/file-foo"
}
}
}
template {
source = "templates/template.ctmpl"
destination = "templates/render.txt"
}
template.ctmpl:
{{ with secret "my-app/data/testsecret" }}
passwd: {{ .Data.data.passwd }}
{{ end }}
I think that the secret exists:
$ vault kv get my-app/testsecret
====== Metadata ======
Key Value
--- -----
created_time 2020-10-22T07:18:48.205108671Z
deletion_time n/a
destroyed false
version 6
===== Data =====
Key Value
--- -----
passwd cat
The secret is kv v2:
$ vault secrets list --detailed |grep my-app
my-app/ kv kv_5898e685 system system false replicated false false map[version:2] n/a cd436e93-db3b-c317-1c31-6967c7b25764
Finally i can solve the issue recreating the secret-id:
vault write -f auth/approle/role/test-role/secret-id
And overwriting the secret_id_file_path (templates/secretid), after that the template has been rendered!!!
vault agent -config=templates/config.hcl
==> Vault agent started! Log data will stream in below:
==> Vault agent configuration:
Cgo: disabled
Log Level: info
Version: Vault v1.5.4
Version Sha: 1a730771ec70149293efe91e1d283b10d255c6d1
2020-10-22T13:28:59.096+0200 [INFO] sink.server: starting sink server
2020-10-22T13:28:59.096+0200 [INFO] auth.handler: starting auth handler
2020-10-22T13:28:59.097+0200 [INFO] auth.handler: authenticating
2020-10-22T13:28:59.096+0200 [INFO] template.server: starting template server
2020/10/22 11:28:59.097331 [INFO] (runner) creating new runner (dry: false, once: false)
2020/10/22 11:28:59.097874 [INFO] (runner) creating watcher
2020-10-22T13:28:59.125+0200 [INFO] auth.handler: authentication successful, sending token to sinks
2020-10-22T13:28:59.125+0200 [INFO] auth.handler: starting renewal process
2020-10-22T13:28:59.125+0200 [INFO] template.server: template server received new token
2020/10/22 11:28:59.125672 [INFO] (runner) stopping
2020/10/22 11:28:59.125710 [INFO] (runner) creating new runner (dry: false, once: false)
2020/10/22 11:28:59.125847 [INFO] (runner) creating watcher
2020/10/22 11:28:59.125955 [INFO] (runner) starting
2020-10-22T13:28:59.161+0200 [INFO] auth.handler: renewed auth token
2020/10/22 11:28:59.251586 [INFO] (runner) rendered "templates/render.txt" => "templates/_env"

How can I mark some ScalaTests so that they only execute when invoked explicitly

I'm new to SBT and scalatest but am wondering how I get some of my org.scalatest._ tests to only execute "on demand".
In SBT I can invoke all of the Unit Tests like sbt:Sprout> test, or all of the IntegrationTests like sbt:Sprout> it:test. I need a way to annotate the tests that allows an sbt:Sprout test invocation to skip them but with some other invocation executes ONLY these tests. Scalatest docs speak of some sbt:Sprout> test-only *RedSuite invocation to allow me to "Categorize" my tests, but its not clear how to leverage that so they DON'T run as Unit Tests. org.scalatest.Tags alone do not get it off the "default" of getting executed when sbt:Sprout> test. I need these to be ignored unless invoked explicitly.
Is this use case possible in ScalaTest through SBT?
You can specify tag names of tests to include or exclude from a run. To specify tags to include, use -n followed by a list of tag names to include. Similarly, to specify tags to exclude, use -l followed by a list of tag names to exclude
(please look here for more info in the official documents).
For example:
package com.test
import org.scalatest.FlatSpec
import org.scalatest.Tag
object IncludeTest extends Tag("com.tags.Include")
object ExcludeTest extends Tag("com.tags.Exclude")
class TestSuite extends FlatSpec {
"Test1" taggedAs(IncludeTest) in {
val sum = 1 + 1
assert(sum === 2)
}
"Test2" taggedAs(ExcludeTest) in {
val minus = 2 - 1
assert(minus === 1)
}
}
To include IncludeTest and exclude ExcludeTest tag, you should do:
test-only org.* -- -n com.tags.Include -l com.tags.Exclude
assume assertion specified inside a fixture-context object could be used to implement conditional-ignore semantics dependant on environmental flag. For example, consider the following IfIgnored fixture
trait IfIgnored extends Assertions {
assume(System.getenv("runIgnoredTest").toBoolean, "!!! TEST IGNORED !!!")
}
which can be instantiated like so
it should "not say goodbye" in new IfIgnored {
Hello.greeting shouldNot be ("goodbye")
}
Now if we define the following settings in build.sbt
Test / fork := true,
Test / envVars := Map("runIgnoredTest" -> "false")
and the following tests
class HelloSpec extends FlatSpec with Matchers {
"The Hello object" should "say hello" in {
Hello.greeting shouldEqual "hello"
}
it should "not say goodbye" in new IfIgnored {
Hello.greeting shouldNot be ("goodbye")
}
it should "not say live long and prosper" in new IfIgnored {
Hello.greeting shouldNot be ("live long and prosper")
}
}
then executing sbt test should output
[info] HelloSpec:
[info] The Hello object
[info] - should say hello
[info] - should not say goodbye !!! CANCELED !!!
[info] scala.Predef.augmentString(java.lang.System.getenv("runIgnoredTest")).toBoolean was false !!! TEST IGNORED !!! (HelloSpec.scala:6)
[info] - should not say live long and prosper !!! CANCELED !!!
[info] scala.Predef.augmentString(java.lang.System.getenv("runIgnoredTest")).toBoolean was false !!! TEST IGNORED !!! (HelloSpec.scala:6)
[info] Run completed in 2 seconds, 389 milliseconds.
[info] Total number of tests run: 1
[info] Suites: completed 1, aborted 0
[info] Tests: succeeded 1, failed 0, canceled 2, ignored 0, pending 0
[info] All tests passed.
where we see only should say hello ran whilst the rest were ignored.
To execute only ignored tests we could define the following custom command testOnlyIgnored:
commands += Command.command("testOnlyIgnored") { state =>
val ignoredTests = List(
""""should not say goodbye"""",
""""should not say live long and prosper""""
).mkString("-z ", " -z ", "")
"""set Test / envVars := Map("runIgnoredTest" -> "true")""" ::
s"""testOnly -- $ignoredTests""" :: state
}
Note how we are making use of -z runner argument to run particular tests, for example,
testOnly -- -z "should not say goodbye" -z "should not say live long and prosper"
Also note how we are manually adding test names to ignoredTests. Now executing sbt testOnlyIgnored should output
[info] HelloSpec:
[info] The Hello object
[info] - should not say goodbye
[info] - should not say live long and prosper
[info] Run completed in 2 seconds, 298 milliseconds.
[info] Total number of tests run: 2
[info] Suites: completed 1, aborted 0
[info] Tests: succeeded 2, failed 0, canceled 0, ignored 0, pending 0
[info] All tests passed.
where we see should say hello was not run whilst all the ignored tests ran.
If we drop the requirement of having to run ignored tests separately, then we can use provided ignore annotation like so
ignore should "not say goodbye" in {
Hello.greeting shouldNot be ("goodbye")
}
which on sbt test outputs
[info] HelloSpec:
[info] The Hello object
[info] - should say hello
[info] - should not say goodbye !!! IGNORED !!!
[info] - should not say live long and prosper !!! IGNORED !!!
[info] Run completed in 2 seconds, 750 milliseconds.
[info] Total number of tests run: 1
[info] Suites: completed 1, aborted 0
[info] Tests: succeeded 1, failed 0, canceled 0, ignored 2, pending 0

Gatling is freezing when I use jsonPath

I have Gatling version 3.0.0-RC4.
I have the following Gatling code
object Signup {
val feeder = csv("phones.csv").circular
var signup = tryMax(2) {
exec(
http("Get details")
.get("/v2/dummy/2")
.check(status.is(200))
)
.feed(feeder)
.exec(
http("Signup")
.post("/v2/user/customer")
.header(HttpHeaderNames.ContentType, HttpHeaderValues.ApplicationJson)
.header(HttpHeaderNames.Accept, HttpHeaderValues.ApplicationJson)
.header("Set-Cookie", "id=2")
.body(StringBody("""{
"email": "rm#gmail.com",
"phone_number": "${phoneNumber}",
"first_name": "Rishi",
"last_name": "Mukherjee",
"pin": "1234",
}""")).asJson
.check(
jsonPath("$.otp_data.otp_uuid").saveAs("lastResponse")))
}.exitHereIfFailed
}
In the line, jsonPath("$.otp_data.otp_uuid").saveAs("OTPUUID"), if I replace that with status.is(200), the code runs just fine. But, with this line, on running the program, it freezes and keeps showing the following
================================================================================
2018-10-12 17:36:11 5s elapsed
---- Requests ------------------------------------------------------------------
> Global (OK=1 KO=0 )
> Get details (OK=1 KO=0 )
---- Signup -------------------------------------------------------------
[--------------------------------------------------------------------------] 0%
waiting: 0 / active: 1 / done: 0
================================================================================
Problem is, I do not get any error or anything that will be helpful to debug. In fact this also happens when I run the included example AdvancedSimulationStep03.scala. What can be the issue or is there anything I may be missing?
So, I had JDK 11. The docs say I should have had JDK 8. Switched to JDK 8 and it got fixed.
Hopefully helps anyone else if they get stuck.

Typesafe Config - reference.conf different behavior?

It seems to me that application.conf and reference.conf behaves differently. I do understand that reference.conf is intended as "safe fall back" configuration which works every time and application.conf is specific. However I would expect that configuration loaded from either of those will behave exactly the same in the sense of parsing the configuration.
What I am facing is that if the configuration is in application.conf it works fine and when the same file is renamed to reference.conf it doesn't work.
2015-03-30 11:35:54,603 [DEBUG] [BackEndServices-akka.actor.default-dispatcher-15] [com.ss.rg.service.ad.AdImporterServiceActor]akka.tcp://BackEndServices#127.0.0.1:2551/user/AdImporterService - Snapshot saved successfully - removing messages and snapshots up to 0 and timestamp: 1427708154584
2015-03-30 11:35:55,037 [DEBUG] [BackEndServices-akka.actor.default-dispatcher-4] [spray.can.server.HttpListener]akka.tcp://BackEndServices#127.0.0.1:2551/user/IO-HTTP/listener-0 - Binding to /0.0.0.0:8080
2015-03-30 11:35:55,054 [DEBUG] [BackEndServices-akka.actor.default-dispatcher-15] [akka.io.TcpListener]akka.tcp://BackEndServices#127.0.0.1:2551/system/IO-TCP/selectors/$a/0 - Successfully bound to /0:0:0:0:0:0:0:0:8080
2015-03-30 11:35:55,056 [INFO ] [BackEndServices-akka.actor.default-dispatcher-4] [spray.can.server.HttpListener]akka.tcp://BackEndServices#127.0.0.1:2551/user/IO-HTTP/listener-0 - Bound to /0.0.0.0:8080
Compared to :
2015-03-30 11:48:34,053 [INFO ] [BackEndServices-akka.actor.default-dispatcher-3] [Cluster(akka://BackEndServices)]Cluster(akka://BackEndServices) - Cluster Node [akka.tcp://BackEndServices#127.0.0.1:2551] - Leader is moving node [akka.tcp://BackEndServices#127.0.0.1:2551] to [Up]
2015-03-30 11:48:36,413 [DEBUG] [BackEndServices-akka.actor.default-dispatcher-15] [spray.can.server.HttpListener]akka.tcp://BackEndServices#127.0.0.1:2551/user/IO-HTTP/listener-0 - Binding to "0.0.0.0":8080
2015-03-30 11:48:36,446 [DEBUG] [BackEndServices-akka.actor.default-dispatcher-3] [akka.io.TcpListener]akka.tcp://BackEndServices#127.0.0.1:2551/system/IO-TCP/selectors/$a/0 - Bind failed for TCP channel on endpoint ["0.0.0.0":8080]: java.net.SocketException: Unresolved address
2015-03-30 11:48:36,446 [WARN ] [BackEndServices-akka.actor.default-dispatcher-15] [spray.can.server.HttpListener]akka.tcp://BackEndServices#127.0.0.1:2551/user/IO-HTTP/listener-0 - Bind to "0.0.0.0":8080 failed
The settle difference are double quotes. And my configuration is specified as follows:
akka {
... standard akka configuration ...
}
webserver.port = 8080
webserver.bindaddress = "0.0.0.0"
Configuration setting is loaded as follows in code:
val webserver_port_key = "webserver.port"
val webserver_bindaddress_key = "webserver.bindaddress"
protected val webserver_bindaddress = ConfigFactory.load().getString(webserver_bindaddress_key)
protected val webserver_port = ConfigFactory.load().getInt(webserver_port_key)
Did I missed something? I double checked that the port 8080 is free when reference.conf fails to bind.
Thanks for hints
UPDATE:
Start with log-config-on-start = on:
- When it is in application.conf
# application.conf: 60-61
"webserver" : {
# application.conf: 61
"bindaddress" : "0.0.0.0",
# application.conf: 60
"port" : 8080
}
- When it is in reference.conf
# reference.conf: 60-61
"webserver" : {
# reference.conf: 61
"bindaddress" : "0.0.0.0",
# reference.conf: 60
"port" : 8080
}
Issue found :
# application.properties
"webserver" : {
# application.properties
"bindaddress" : "\"0.0.0.0\"",
# application.properties
"port" : "8080"
}
It seems that the bindaddress is of a different type because it shows up differently in logs.
In either case enable Akka full config printing on start with this setting in your config:
log-config-on-start = on
Then compare both configurations to see where they mismatch. They should work the same way if the are the same. I suspect that the way you define bindaddress is different, i.e. String vs some other type.

Sbt always does full rebuild because of modified binary dependency rt.jar

Sbt always does full rebuild because of modified binary dependency: rt.jar:
[debug]
[debug] Initial source changes:
[debug] removed:Set()
[debug] added: Set()
[debug] modified: Set()
[debug] Removed products: Set()
[debug] Modified external sources: Set()
[debug] Modified binary dependencies: Set(C:\Program Files\Java\jdk1.6.0_37\jre\lib\rt.jar)
[debug] Initial directly invalidated sources: Set()
Obviously, rt.jar wasn't changed, its created/accesses/modified dates are the same and quite old.
It's in c:\Program Files\Java\jdk1.6.0_37\jre\lib\
JAVA_HOME is set as C:\Progra~1\Java\jdk1.6.0_37
JAVA_HOME/bin is in PATH.
Any ideas why sbt thinks rt.jar was changed?
I had JAVA_HOME set to C:\Progra~1\Java\jdk1.6.0_37 and sbt resolved the dependency as C:\Program Files\Java\jdk1.6.0_37\jre\lib\rt.jar. Sbt uses java.io.File.equals() which is not correct in this case:
In sbt/compile/inc/Incremental.scala:
def externalBinaryModified(entry: String => Option[File], analysis: File => Option[Analysis], previous: Stamps, current: ReadStamps)(implicit equivS: Equiv[Stamp]): File => Boolean =
dependsOn =>
analysis(dependsOn).isEmpty &&
orTrue(
for {
name <- previous.className(dependsOn)
_ = println("Name: " + name)
e <- entry(name)
_ = println("entry: " + e)
} yield {
val resolved = Locate.resolve(e, name)
println("resolved: " + resolved)
println("dependsOn: " + dependsOn)
println("resolved != dependsOn: " + (resolved != dependsOn))
(resolved != dependsOn) || !equivS.equiv(previous.binary(dependsOn), current.binary(resolved))
}
)
gives the following output:
Name: java.lang.Object
entry: c:\Progra~1\Java\jdk1.6.0_37\jre\lib\rt.jar
resolved: c:\Progra~1\Java\jdk1.6.0_37\jre\lib\rt.jar
dependsOn: c:\Program Files\Java\jdk1.6.0_37\jre\lib\rt.jar
resolved != dependsOn: true
Thus, sbt always thinks rt.jar was changed.
Workaround would be setting JAVA_HOME to "c:\Program Files\Java\jdk1.6.0_37"
Solution would be to do:
resolved.getCanonicalPath != dependsOn.getCanonicalPath