We have this setup where we call a webservice to create a queue, and receive the queue name from the response.
Then we set up a SimpleMessageListenerContainer and set the queue name there, and then start it.
However, from time to time, the queue is deleted - resulting in a "404 could not declare queue XXXXXXXXX" error. In these cases, I need to call the webservice again and add the new QueueName to the SimpleMessageListenerContainer and then removing the old one.
The only way I figured out trigger any code to handle this was to create a custom CachedConnectionFactory and overriding the shutdownCompleted method.
However, shutdownCompleted seems to trigger when the SimpleMessageListenerContainer switches over as well, so it sticks in a loop. The ShutdownSignalException sent into shutdownCompleted does not seem to look any different if the trigger is external from the server or from the client handling the new queue, so I can't figure out how to skip the handling on the "second" go.
So what is the usual way to detect and run custom handling when the server kills the queue?
The container publishes a ListenerContainerConsumerFailedEvent when the listener fails.
Add an ApplicationListener<ListenerContainerConsumerFailedEvent>, stop the container, change the queues and restart.
You will likely get multiple events because, by default, the container will try to reconnect 3 times before giving up and stopping itself.
Related
I am aware of the fact that when both microtask and event queues of an isolate are empty, the isolate is killed. However, I'm not able to find a reference on the documentation of how a worker isolate can be killed under certain circumstances.
Context
Let's make this example:
Future<void> main() {
final receivePort = ReceivePort();
final worker = await Isolate.spawn<SendPort>((_) {}, receivePort.sendPort);
await runMyProgram(receivePort, worker);
}
Here the main isolate is creating a new one (worker) and then the program starts doing stuff.
Question
How do I manually kill the newly spawned isolate when it's not needed anymore? I wasn't able to explicitly find this information on the documentation so I am kind of guessing. Do I have to do this?
receivePort.close();
worker.kill();
Or is it enough to just close the port, like this?
receivePort.close();
Note
I thought about this. If the worker isolate has both queues (microtask and event) empty and I close the receive port, it should be killed automatically. If this is the case, calling receivePort.close() should be enough!
If you want to make sure the child isolate shuts down, even if it's in the middle of doing something, you'll want to call Isolate.kill().
However, as you've already pointed out, an isolate will exit on its own if it has no more events to process and it holds no open ports (e.g., timers, open sockets, isolate ports, etc). For most cases, this is the ideal way to dispose of an isolate when it's no longer used since it eliminates the risk of killing the isolate while it's in the middle of doing something important.
Assuming your child isolate is good about cleaning up its own open ports when it's done doing what it needs to do, receivePort.close() should be enough for you to let it shut down.
You can kill an isolate from the outside, using the Isolate.kill method on an Isolate object representing that isolate.
(That's why you should be careful about giving away such isolate objects, and why you can create an isolate object without the "kill" capability, that you can more safely pass around.)
You can immediately kill an isolate from the inside using the static Isolate.exit.
Or using Isolate.current.kill. It's like Process.exit, but only for a single isolate.
Or you can make sure you have closed every open receive port in the isolate, and stopped doing anything.
That's the usual approach, but it can fail if you run code provided by others in your isolate. They might open receive ports or start periodic timers which run forever, and that you know nothing about.
(You can try to contain that code in a Zone where you control timers, but that won't stop them from creating receive ports, and they can always access Zone.root directly to leave the zone you put them in.)
Or someone might have Isolate.pauseed your isolate, so the worker code won't run.
If I wanted to be absolutely certain that an isolate is killed,
I'd start out by communicating with my own code running in that isolate (the port receiving worker instructions) and tell it to shut down nicely, as a part of the protocol I am already using to communicate.
The worker code can choose to use Isolate.exit when it's done, or just close all its own resources and hope it's enough. I'd probably tend to use Isolate.exit, but only after waiting for existing worker tasks getting done.
Such a worker task might be hanging (waiting for a future which will never complete). Or it might be live-locking everything by being stuck in a while (true){..can't stop, won't stop!..}. In that case, the waiting should have a timeout.
Because of that, I'd also listen for the isolate to shut down, using Isolate.addOnExitHandler, and start a timer for some reasonable duration, and if I haven't received an "on exit" notification before the timer runs out, or some feedback on the worker shutdown request telling me that things are fine, I'd escalate to isolate.kill(priority: Isolate.immediate); which can kill even a while (true) ... loop.
Tested: In order to avoid repeated execution of some code (like chrome.contextMenus.create repeated execution makes
Unchecked runtime.lastError: Cannot create item with duplicate id
), it needs to be moved into chrome.runtime.onInstalled.addListener.
But some code (like chrome.action.onClicked.addListener) moved into chrome.runtime.onInstalled.addListener won't run on next wakeup.
If chrome.action.onClicked.addListener is placed at the top level of the service worker,
will the Listener be added again every time the service worker wakes up,
Will there be multiple duplicate listeners?
will the functions in the new added Listener and in Listener added previous be executed both?
https://developer.chrome.com/docs/extensions/mv3/service_workers/ saying:
A background service worker is loaded when it is needed, and unloaded when it goes idle. Some examples include:
The extension is first installed or updated to a new version.
The background page was listening for an event, and the event is
dispatched.
A content script or other extension sends a message.
Another view in the extension, such as a popup, calls
runtime.getBackgroundPage.
says 'unloaded when it goes idle', will the Listener added previous be unloaded too? ___if so,how awaking service worker again?
or only unload the functions in Listener added previous, and reserve the Listener empty shell just for awaking service worker ?
Yes, it reruns anew.
No, there'll be no duplicate listeners.
No multiple threads, no sleeping/suspending/resuming.
The confusion is caused by a rather inept description in the old version of the documentation, now it's rewritten. What actually happens is that after a certain timeout the service worker is simply terminated. It doesn't "unload" or "resume". It "terminates completely" and "starts fresh".
When it terminates, the JavaScript environment disappears (JS listeners, variables, everything).
When it's started by the browser in reaction to an event to which you subscribed via addListener in the previous run of the SW, your SW script runs in its entirety. Each addListener for a chrome event registers this listener internally. Then the event that woke the worker will be dispatched to the listeners. This is why it is important to register the listeners synchronously in the first task of the event loop when the script starts (the old documentation used a rather arcane term "top-level" from the makers of V8 and oversimplified it to the need to declare the listeners in the global scope of the script, which is not mandatory because you can certainly do it inside a function call as long as it's synchronous).
The contextMenus API is different: the data is saved inside Chrome's internal preferences so there's no need to recreate it on each run, doing it inside chrome.runtime.onInstalled is sufficient. Firefox doesn't save them yet, but I guess they will do it once they implement MV3.
P.S.
The lifetime duration is 30 seconds after the last incoming external event. Using a runtime port adds another 5 minutes to the timeout. Using native host messaging keeps the service worker alive indefinitely, but it is also possible to emulate a persistent service worker to a degree even without native messaging: more info.
Another view in the extension, such as a popup, calls runtime.getBackgroundPage.
This is not true anymore in MV3.
An app I am working on requires creating a container object on a server and inserting items into that container. I don't want to create the container object until the first item needs to be inserted. However, creating the container object requires some initialization that may take a little time. While that container is still initializing the user can still to send insertion requests that aren't getting handled because the container isn't ready yet. I have two main questions:
Should this be dealt with on the client or server side?
What is the best practice for dealing with kind of this issue?
Essentially, I need to ensure my initial createContainer data task in complete before any insertItem requests are sent.
Addition Information
An insertItem request is sent by clicking on a corresponding tableViewCell. The first tableViewCell a user clicks on sends a createContainer request that creates a container holding the first item.
For a container holding n items, the request should be sent in the following order:
createContainer(Container(with: item1)
insertItem(item2)
...
insertItem(itemn)
After the first request completes, the remaining n – 1 requests may complete in any order.
My Thoughts
It sounds like I want the createContainer request to be handled synchronously while the insertItem request should be handled asynchronously. I'm not sure if that is the best approach or even how to perform that appropriately, so any guidance would be greatly appreciated.
You can use a NSOperationQueue and multiple NSOperations to implement your desired behavior. A NSOperation instance can be dependent on the completion of another NSOperation instance:
dependencies
An array of the operation objects that must finish
executing before the current object can begin executing.
For your example this would mean that the insertItem-Operations are dependent on the createContainer operation.
When you add all those operations to a NSOperationQueue your createContainer operation will run first. When it has finished, the other operations will start running as their dependencies are now satisfied. You can also control how many operations you want to run concurrently using maxConcurrentOperationCount on NSOperationQueue.
As you will be using asynchronous API in your NSOperations you will need to implement a ConcurrentOperation and handle the state changes yourself. The API Reference is explaining this in pretty good detail.
Check out the API Reference for NSOperation for further information.
There is also a nice NSHipster article on NSOperations.
Adding to the NSOperationQueue answer, it's sometimes difficult to manually manage all the state changes that an NSOperation requires to handle something asynchronous like a network call.
To simplify that, you can use a Swift Library called Overdrive. It's an amazing library in which you simply subclass a Task class and write your network code in the run() function. And when you're done, you simply call self.finish to finish the task. Here's an example: Just create a simple download task:
Then, just add it to the queue.
You can also add dependencies between tasks, which basically solves your use case.
Hope this helps.
In my application I use a winevent hook to get focus changes system-wide. Because there are no timing problems, I use an out-of-context hook, even if I know that it is slow. If there are multiple events fired quickly on after another, the system queues them and gives them to the hook callback function in the right order.
Now I would like to process only the newest focus change. So if there are already other messages in the queue, I want the callback function to stop and restart with the parameters of the newest message. Is there a way to do that?
When you receive a focus change, create an asynchronous notification to yourself, and cancel any previous notification(s) that may still be pending.
You can use PostMessage() and PeekMessage(PM_REMOVE) for that. Post a custom message to yourself, removing any previous custom message(s) that are still in the queue.
Or, you can use TTimer/SetTimer() to (re)start a timer on each focus change, and then process the last change when the timer elapses.
Either way, only the last notification will be processed once the messages slow down.
I am developing a project for BB. The application works with the network and sends / receives data via HTTP. Now I use the queue and queue manager. Manager starts with a background thread and works in while (true) loop, checking the queue for new transactions to the server. If the queue is not empty, then the transaction is executed, otherwise the manager goes to sleep for 200 ms.
The process of the transaction as follows:
- Runs another thread (using the Runnable), which opens a connection to the network and first thread waiting for background thread or timeout (and for that we need a loop), which we set.
- If the connection is established, then starts another thread (using the Runnable), which runs getResponseCode (), and first thread waiting for background thread or timeout (and for that we need a loop), which we set.
Before it, we showing popup window with wait-rotating-image, and after it is removed. It synchronized via Application.getEventLock ().
Iit unstable sometimes and thread sleeps for a long time ignore timeout-waiting-loop.
I would like to know how valid such an approach, what advice and best-practice is, what is your experience?
I use 4.5, 4.6, 4.7 and 5.0.
The lock returned by Application.getEventLock() should only be used for code that modifies the UI or UI components - it's the lock used by the event dispatcher. You should not be using it for background tasks such as HTTP processing. If you want to synchronize that code, it would be best to just create your own lock object.
You do not need that many threads, your EDT (event dispatch thread a.k.a main thread) should insert he job (some runnable class) into a queue and use wait/notify to inform a dedicated worker thread, that is responsible for network transaction, to check the queue.
The worker thread will be responsible for opening connection, writing to connection and reading from it.
For information about wait/notify mechanism check out:
A simple scenario using wait() and notify() in java
Due to the fact that you can't update the UI using the worker thread, Once the network transaction is completed you can update the UI layer using InvokeLater
For more details go to http://www.blackberry.com/developers/docs/5.0.0api/net/rim/device/api/system/Application.html#invokeLater(java.lang.Runnable)
you can set a timeout in the HTTPConnection itself, but if you don't want to rely on that mechanism, you can schedule a TimerTask that will execute after some time and handle the timeout in case no response is received.
Once the response is received all you need to do is cancel the TimerTask so that the timeout will not be triggered.
Check out http://www.blackberry.com/developers/docs/4.0api/java/util/TimerTask.html