Below is a part of code where the discrepancy is seen. The problem that i am scratching my head over is this. I am confused over why the state of a registration changes from Active to Inactive after leaving the withNewSession block.
Transaction.withNewSession{ session ->
if (saleId?.isLong()){
invoices = registrationService.completeSale(saleId.toLong(), transactionResponse)
}
println Registration.last().status //ACTIVE
}
println Registration.last().status //INACTIVE
The following part is optional but just for reference i have pasted it. One thing the completeSale method does is it calls the following method which will activate registrations.
void activateRegistrations(SaleInvoice invoice){
Assert.notNull(invoice, 'SaleInvoice cannot be null when activating registrations.')
List<Registration> registrations = this.findRegistrationsBySaleInvoice(invoice)
registrations.each{
it.status = EntityStatus.ACTIVE
it.save()
}
}
Now, my doubt is why the first println statement i.e println Registration.last().status //ACTIVE will print ACTIVE and the second will print INACTIVE. I am guessing the Transaction.withNewSession has to do with it since the change happens in the boundary of
the withNewSession block. How can withNewSession be responsible for this apparent discrepancy?
Related
This is the overall flow of my setup:
void ScriptPlayer::new_lua_state() {
lua = {};
lua.open_libraries(sol::lib::base, sol::lib::package, sol::lib::coroutine, sol::lib::math);
[...]
// Proceeds to initialize the state with usertype definitions and values
}
void ScriptPlayer::play(std::string path) {
main_coroutine = sol::nil;
script_env = sol::environment(lua, sol::create, lua.globals());
auto result = lua.load_file(path);
main_coroutine = sol::coroutine(result);
script_env.set_on(main_coroutine);
}
void ScriptPlayer::update() {
if (main_coroutine) {
main_coroutine();
}
}
"new_lua_state" is called once at the beginning of everything, then "play" is called anytime I want to execute a new lua script (that yields). "update" is executed every frame, and progresses the coroutine until it's finished, at which point it stops.
The problem:
If I call "play" while the previous script coroutine has yielded but hasn't yet finished, I expect lua to discard the whole environment and create a new one, discard the old coroutine, parse the script again, create a brand new coroutine and start its execution from the beginning.
What I get instead is that the coroutine will STILL be running from the state of the previous script's coroutine (which should be completely discarded) and not from the very beginning.
How is this possible? Where exactly is the state of the coroutine stored?
I tried wrapping the state with a thread, I tried calling lua.clear_stack but nothing made any difference in the fact that the new coroutine never starts from the beginning of the function when I re-parse the script and re-create the sol::coroutine object.
Any clarification is hugely appreciated.
Here was the solution:
https://github.com/ThePhD/sol2/issues/1061
Apparently my attempt of wrapping the state with a thread was faulty, because that was exactly the thing to do.
So to solve this, here's what I did:
void ScriptPlayer::play(std::string path) {
script_env = sol::nil;
main_coroutine = sol::nil;
script_thread = sol::thread::create(lua);
script_env = sol::environment(script_thread.state(), sol::create,
script_thread.state().globals());
auto result = script_thread.state().load_file(path);
main_coroutine = sol::coroutine(result);
script_env.set_on(main_coroutine);
}
One this that still blows my mind is that if I remove the second line (that reset the C-held reference to the lua coroutine), the result goes back to wrongly resuming the previous coroutine, despite that very same variable being set to a different value shortly after..
This baffles me deeply.
I need to create dependent API calls where the second one needs a value returned by the first one. First thing that comes to mind is using flatMap
ApiManager.shared
.createReport(report: report)
.flatMap { (report) -> Observable<Report> in
return ApiManager.shared.createReportStep(reportID: report.ID)
}
createReport returns Observable<Report> where after successfull call returns updated Report model(with ID), after that I need to call API to create report step, where report.ID is needed.
Everything looks and works fine with that code, but the problem comes when I need to do something after each of these steps(createReport and createReportStep). I placed code in onNext block, but it is called only once, after both of the steps are completed.
Is there a way to receive onNext signal after both steps? I could use something like this:
ApiManager.shared
.createReport(report: report)
.concat(ApiManager.shared.createReportStep(reportID: report.ID))
Which would emmit two signals like I want, but then again where do I get updated report.ID from to pass to createReportStep?
If you don't mind the time component and only need to have access to both report and what is returned by createReportStep(reportID:), you could go with creating a tuple in flatMap's block
ApiManager.shared
.createReport(report: report)
.flatMap { (report) -> Observable<Report> in
return ApiManager.shared.createReportStep(reportID: report.ID)
.map { (report, $0) }
}
The resulting observable would contain both results in a tuple.
If the time component is important, you could do the following
let report = ApiManager.shared
.createReport(report: report)
.share()
let reportStep = report.map { $0.ID }.flatMap(ApiManager.shared.createReportStep)
Observable.concat([report, reportStep])
Here, the important bit is the share call. It will ensure createReport performs its work only once, but you would have two next events as requested.
On Chrome Mac. I am trying to register a ServiceWorker and set a variable to it. When I call register() and the service worker has not previously been installed, the "active" property seems to be set to null immediately and then get initialized (asynchronously?) very soon after.
var sw = null;
navigator.serviceWorker.register('preview/sw.js', {scope: 'preview/'}).
then(function(registration) {
console.dir(registration);
sw = registration.active;
if (!sw) {
console.log('wat');
console.dir(registration);
}
});
In other words, I get into the if-block the first time the service worker has been installed. The console shows the active property as being set equal to the ServiceWorker in both console.dir() commands, yet the sw variable is null.
Refreshing the page fixes the problem. Anybody know what could be causing this?
For the first visit you're describing, the registration is not yet active when that promise resolves but it is "installing", so the registration's installing property will return a service worker.
Since no service worker is in the waiting state, it will then transition to activating then active. So you're right in that registration property is not initially active but on refresh, it will be.
The following code will illustrate:
navigator.serviceWorker.register('/serviceworker.js').then(onRegistration);
function onRegistration(registration) {
if (registration.waiting) {
console.log('waiting', registration.waiting);
registration.waiting.addEventListener('statechange', onStateChange('waiting'));
}
if (registration.installing) {
console.log('installing', registration.installing);
registration.installing.addEventListener('statechange', onStateChange('installing'));
}
if (registration.active) {
console.log('active', registration.active);
registration.active.addEventListener('statechange', onStateChange('active'));
}
}
function onStateChange(from) {
return function(e) {
console.log('statechange initial state ', from, 'changed to', e.target.state);
}
}
On first visit, the console.log output would be:
installing ServiceWorker {scriptURL: "http://...", state: "installing", onstatechange: null, onerror: null}
statechange initial state installing changed to installed
statechange initial state installing changed to activating
statechange initial state installing changed to activated
The state changes happen asynchronously as you observed.
The service worker is registered, but it isn't active yet and it isn't controlling your page yet.
If you want your service worker to become active, you can call the function skipWaiting in the install event handler.
If you want your service worker to control the page as soon as it becomes active, you can use the Clients.claim function in the activate event handler.
You can see an example in the ServiceWorker Cookbook Immediate Claim recipe.
I want to update an existent Node in the db.
I could correctly create a node but can't update an existent one.
try (Transaction tx = template.getGraphDatabaseService().beginTx()) {
Node node = repository.findNodeUsingId("n1");
if(node != null){
//Modify some properties using setProperty
node.setProperty("name","P");
//How should I do to save the modified node object?
}else{
//Create the node
//This part works fine
node = template.createNode();
node.setProperty("name", "T");
}
tx.success();
}
You don't have to save the modified object.
Once setProperty has been called, your node property has been set in the current Transaction.
The only thing you are missing here is to close the Transaction, check this (from Neo4j Javadoc) about Transaction.close():
Commits or marks this transaction for rollback, depending on whether
success() or failure() has been previously invoked. All
ResourceIterables that where returned from operations executed inside
this transaction will be automatically closed by this method. This
method comes from AutoCloseable so that a Transaction can participate
in try-with-resource statements. It will not throw any declared
exception. Invoking this method (which is unnecessary when in
try-with-resource statement) or finish() has the exact same effect.
Consider the following code:
if (!serpKeyword) {
serpKeyword = new SerpKeyword(
keyword: searchKeyword,
geoKeyword: geoKeyword,
concatenation: concatenation,
locale: locale
)
serpKeyword.save(flush: true, failOnError: true)
}
serpService.submitKeyword(serpKeyword, false)
Here's the submitKeyword method:
#Transactional(propagation = Propagation.REQUIRES_NEW)
boolean submitKeyword(keywordToSubmit, boolean reset) {
def keyword = SerpKeyword.get(keywordToSubmit.id)
No error is raised when I call serpKeyword.save, but when I get into the submitKeyword method, SerpKeyword.get(keywordToSubmit.id) returns null. What could be preventing this from saving?
Edit
Changing REQUIRES_NEW to REQUIRED seems to do the trick. Here's what I think is happening.
The code that calls serpService.submitKeyword is located within a service method. From what I understand, service method's have a default propagation strategy of REQUIRED. Since all this database writes are happening within the context of a transaction, the writes are queued up in the database, but not actually executed against the database until the transaction is completed, according to the docs:
Note that flushing is not the same as committing a transaction. If
your actions are performed in the context of a transaction, flushing
will execute SQL updates but the database will save the changes in its
transaction queue and only finalize the updates when the transaction
commits.
We call serpService.submitKeyword before our transaction is actually finished. That method starts a completely new transaction where our serpKeyword is not available. Changing it to REQUIRED works because we are now operating within the context of our parent transaction.
I think some part of the stack is being lazy. I've ran into this behavior with Hibernate, if that's what you're using. I'm not sure it's an approved maneuver, but you could clear the session before calling submitKeyword like so:
long keywordId = serpKeyword.id
SerpKeyword.withSession{it.clear()}
serpService.submitKeyword(keywordId, false)
And then change the method to:
#Transactional(propagation = Propagation.REQUIRES_NEW)
boolean submitKeyword(keywordId, boolean reset) {
def keyword = SerpKeyword.get(keywordId)
Then I bet the .get() will work. If you have other objects in the session you need. You will need to lift those out by storing their id's and .get()ing them as well.