I'm trying to use the executor plugin in grails but I'm having a problem which I am not able to solve.
Basically, i have a list of links that I want to crawl and I was having an issue where it was always crawling the same ones, so I simplified my example to this:
List offerLinks = getOfferLinks(parser)
offerLinks.each{println it}
List futures = new Vector()
for (def link : offerLinks) {
def future = callAsync {
return link
}
futures.add(future)
}
futures.each{println "FUTURE " + it.get()}
This is what gets printed in the console
bt-ofrd-acciona-6633344.htm?
bt-ofrd-celiasiffredi-293068.htm?
bt-ofrd-clahubiz-92924.htm?
bt-ofrd-haruko-1672632.htm?
FUTURE bt-ofrd-clahubiz-92924.htm?
FUTURE bt-ofrd-haruko-1672632.htm?
FUTURE bt-ofrd-haruko-1672632.htm?
FUTURE bt-ofrd-haruko-1672632.htm?
The first 4 results are for the offerLinks.each{println it} code
The last 4 are for futures.each{println "FUTURE " + it.get()}
What I'm trying to find out is why putting those links in the callAsync block and retrieving them from the future objects make them take the last value, it seems like its replacing the already created future objects?
This piece of code is inside a service called by a controller.
I appreciate any help you can give me. Thanks
Update:
I'm thinking there is some kind of problem in the Java executor API... or maybe I'm don't fully understand how it really works?
Here is another test changing the code to use invokeAll:
def threadPool = Executors.newCachedThreadPool()
List offerLinks = getOfferLinks(parser)
List lista = new ArrayList()
for (enlace in offerLinks) {
println "link " + enlace
lista.add({enlace} as Callable)
}
def futures = threadPool.invokeAll(lista)
futures.each{println "FUTURE " + it.get()}
This is what gets printed
link /bt-ofrd-implementar-192996.htm?
link /bt-ofrd-cdonini-864908.htm?
link /bt-ofrd-hvtalent-1493932.htm?
link /bt-ofrd-dbak-1358120.htm?
link /bt-ofrd-hexacta-100072.htm?
link /bt-ofrd-ccibelli-457472.htm?
FUTURE /bt-ofrd-ccibelli-457472.htm?
FUTURE /bt-ofrd-ccibelli-457472.htm?
FUTURE /bt-ofrd-ccibelli-457472.htm?
FUTURE /bt-ofrd-ccibelli-457472.htm?
FUTURE /bt-ofrd-ccibelli-457472.htm?
FUTURE /bt-ofrd-ccibelli-457472.htm?
It looks to me like something odd is going on with the scope of variables defined outside the closure but referred to from inside, it's not "closing" properly. Does it work any better if you do
def threadPool = Executors.newCachedThreadPool()
List offerLinks = getOfferLinks(parser)
List lista = new ArrayList()
for (enlace in offerLinks) {
println "link " + enlace
lista.add(({ it }.curry(enlace)) as Callable)
}
def futures = threadPool.invokeAll(lista)
futures.each{println "FUTURE " + it.get()}
This should ensure that the right thing gets passed into the closure, and the closure itself doesn't need to refer to the externally-defined enlace variable directly.
This doesn't on its own explain why what you've already tried didn't work, but it might give you a workaround.
Edit: I didn't spot this before, but I now notice that you aren't declaring enlace in that for loop, so it's not a local variable and the closures are (correctly) referring to a single shared variable rather than "closing" over the value in a particular loop iteration. It should work if you use a construction like this instead:
def tasks = offerLinks.collect { link ->
println "link " + enlace
return ({ link } as Callable)
}
def futures = threadPool.invokeAll(tasks)
futures.each{println "FUTURE " + it.get()}
where the link variable is local to the collect closure, so the {...} as Callable will close over the correct value. The equivalent in terms of callAsync would be to use
List futures = offerLinks.collect { link ->
callAsync { link }
}
Is this better?
List offerLinks = getOfferLinks(parser)
offerLinks.each{println it}
List futures = new Vector()
for (def link : offerLinks) {
futures.add( callAsync {
return link
}
)
}
futures.each{println "FUTURE " + it.get()}
Sounds like the same phenonemon I just experienced, see this answer.
For me, the problem was that "The current thread's MDC is inherited by newly spawned threads". I don't know the why of that, so I can't tell why you may bump into the same problem - but maybe because you retrieve the links from a service?
Related
I am trying to get a document from a form here, but my script out is missing. Am i doing anything wrong here. This seems to work when there is more than on argument but it is just one it seems not to be working
try:
documents = {}
if "Select which supporting documentation you would like to accompany your motivation letter" in input_data['checkbox']:
documents['doc1']="https://essentialmedicalguidance.s3.eu-central-1.amazonaws.com/brand/Eli+Lilly/Trulicity/VAE_Trulicity+Package+Insert.pdf"
return documents
except:
return {'empty' : True}
The function always has to return (or set) data. In the case where 'Select which...' is not in input_data['checkbox'], then nothing is returned.
Try something like this instead, which will be more consistent (if you add more fields):
result = {}
if 'Select which...' in input_data['checkbox']:
result['doc1'] = 'https://ess...'
return result
This way, your output is still conditional, but something is always returned.
Currently, im using findAll. But I dont need the list that it returns. return doesnt work in each so I could not use it.
In grails, is there a loop that matched my need or should I use for loop?
If it makes any sense I believe you are trying to use it as a state rather than wanting the results in which case I doubt you would need findAll
so something like
def user = User.findByUsername('username')
Now
if you did
if (user) {
//do something
}
That would tell you there is something found or maybe:
int size = (User.findAllByUsername('username')?.size()) ?: 0
println "found ${size} records"
Ofcourse if you did
User.findAll{}
Thats all then you iterate through it find what you want
instead if you did
//def aa = User.findAll{user=='username'}?.size()
def aa = User.findAll{user=='username'}
if (aa ) {
println "we have something "
}
The examples in the RxJS README seem to suggest we have to subscribe to a source. In other words: we wait for the source to send events. In that sense, sources seem to be push-based: the source decides when it creates new items.
This contrasts, however, with iterators, where strictly speaking new items need only be created when requested, i.e., when a call is made to next(). This is pull-based behavior, also known as lazy generation.
For instance, a stream could return all Wikipedia pages for prime numbers. The items are only generated when you ask for them, because generating all of them upfront is quite an investment, and maybe only 2 or 3 of them might be read anyway.
Can RxJS also have such pull-based behavior, so that new items are only generated when you ask for them?
The page on backpressure seems to indicate that this is not possible yet.
Short answer is no.
RxJS is designed for reactive applications so as you already mentioned if you need pull-based semantics you should be using an Iterator instead of an Observable. Observables are designed to be the push-based counterparts to the iterator, so they really occupy different spaces algorithmically speaking.
Obviously, I can't say this will never happen, because that is something the community will decide. But as far as I know 1) the semantics for this case just aren't that good and 2) this runs counter to the idea of reacting to data.
A pretty good synopsis can be found here. It is for Rx.Net but the concepts are similarly applicable to RxJS.
Controlled observable from the page you referenced can change a push observable to pull.
var controlled = source.controlled();
// this callback will only be invoked after controlled.request()
controlled.subscribe(n => {
log("controlled: " + n);
// do some work, then signal for next value
setTimeout(() => controlled.request(1), 2500);
});
controlled.request(1);
A truly synchronous iterator is not possible, as it would block when the source was not emitting.
In the snippet below, the controlled subscriber only gets a single item when it signals, and it does not skip any values.
var output = document.getElementById("output");
var log = function(str) {
output.value += "\n" + str;
output.scrollTop = output.scrollHeight;
};
var source = Rx.Observable.timer(0, 1000);
source.subscribe(n => log("source: " + n));
var controlled = source.controlled();
// this callback will only be invoked after controlled.request()
controlled.subscribe(n => {
log("controlled: " + n);
// do some work, then signal for next value
setTimeout(() => controlled.request(1), 2500);
});
controlled.request(1);
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/2.5.2/rx.all.js"></script>
<body>
<textarea id="output" style="width:150px; height: 150px"></textarea>
</body>
I'm quite late to the party, but it's actually very simple to combine generators with observables. You can pull a value from a generator function by syncing it with a source observable:
const fib = fibonacci()
interval(500).pipe(
map(() => fib.next())
)
.subscribe(console.log)
Generator implementation for reference:
function* fibonacci() {
let v1 = 1
let v2 = 1
while (true) {
const res = v1
v1 = v2
v2 = v1 + res
yield res
}
}
I have a WoW/LUA script that I am attempting to start, but it seems to conflict with the Stubby addon, which is a part of the Auctioneer addon, I believe. Here is the message I receive:
Error occured in: Stubby Count: 1 Message: Error: Original call failed
after running hooks for: ChatFrame_OnEvent Usage:
SendChatMessage(text [,type] [,language] [,targetPlayer]) Debug:
(tail call): ? [string ":OnEvent"]:1:
[string ":OnEvent"]:1
Now, the only thing that's happening in the conflicting addon is:
ChatFrame_AddMessageEventFilter("CHAT_MSG_PARTY", partyMsg)
The code within partyMsg is very simple as well:
local function partyMsg(msg,author,language,lineID,senderGUID)
if (store ~= msg) then
SendChatMessage(msg,"SAY",nil,nil);
end
store = msg;
end
Is this error due to two addons both trying to filter the chat frame? If so, how can this be done? It seems odd to me that Blizzard would have such a simple and yet important concept limited to one addon.
I think I see what happened here.
The reference you were using, Events/Communication, shows only the specific parameters for a particular event, regardless of context.
The context is usually an OnEvent handler.
The ChatFrame_AddMessageEventFilter function lets you use the chat frame's OnEvent handler instead of your own for chat frame events, and has well defined parameters for filters you add.
An OnEvent handler might look like:
function Foo_OnEvent(self, event, ...)
A 'ChatFrame' filter must look like this, for the first two parameters:
function Foo_ChatFrameFilter(self, event, msg, ...)
The ChatFrame filter is specific. For OnEvent however, you can make a Lua 'handler' that doesnt care about what frame it came from:
<OnEvent>
MyEventHandler(event, ...)
</OnEvent>
For the sake of completion, I will include the entire source of this addon:
local function partyMsg(someTable,msgType,msg,user,language,...)
if (store ~= msg) then
SendChatMessage(user .. " just said: ".. msg .. " using that sneaky " .. language .. " language.");
end
store = msg;
return false;
end
ChatFrame_AddMessageEventFilter("CHAT_MSG_PARTY", partyMsg)
ChatFrame_AddMessageEventFilter("CHAT_MSG_PARTY_LEADER",partyMsg)
There were a couple issues with the original code:
1) I was using WoWWiki to get my information, and first, I read it incorrectly. lineID and senderGUID are not the 4th and 5th arguments. Then, beyond this, WoWWiki is incorrect on this page in general. The correct arguments are listed above in the source. The first argument, a table, I am unsure of its purpose. In any case, this code now works fully.
I'm trying to get a handle on how OOP is done in Lua, and I thought I had a simple way to do it but it isn't working and I'm just not seeing the reason. Here's what I'm trying:
Person = { };
function Person:newPerson(inName)
print(inName);
p = { };
p.myName = inName;
function p:sayHello()
print ("Hello, my name is " .. self.myName);
end
return p;
end
Frank = Person.newPerson("Frank");
Frank:sayHello();
FYI, I'm working with the Corona SDK, although I am assuming that doesn't make a difference (except that's where print() comes from I believe). In any case, the part that's killing me is that inName is nil as reported by print(inName)... therefore, myName is obviously set to nil so calls to sayHello() fail (although they work fine if I hardcode a value for myName, which leads me to think the basic structure I'm trying is sound, but I've got to be missing something simple). It looks, as far as I can tell, like the value of inName is not being set when newPerson() is called, but I can't for the life of me figure out why; I don't see why it's not just like any other function call.
Any help would be appreciated. Thanks!
Remember that this:
function Person:newPerson(inName)
Is equivalent to this:
function Person.newPerson(self, inName)
Therefore, when you do this:
Person.newPerson("Frank");
You are passing one parameter to a function that expects two. You probably don't want newPerson to be created with :.
Try
Frank = Person:newPerson("Frank");