I’m testing my license flow with hosted-floating licenses, and hoping you can explain why what I’m doing is wrong.
According to the documentation, the only change necessary is that on shutdown, I have to call DeactivateLicense() to release a float license back to the server. I’ve done this, however it seems that licensing a hosted-floating system does not store or apply the license key locally like the standard node-locked license does, as my application always asks me for the key. Do I need to call SetLicenseKey with every run? This is not mentioned in the documentation, is a significant departure from node-locked, and makes using floats rather cumbersome.
DeactivateLicense() function doesn’t reset the license key in case of hosted-floating license type.
Calling DeactivateLicense() when application closes and license type is “hosted-floating”, it still removes the license key and requires the user to enter it again on next start. I’m using LexActivator version 3.15.0.
Can you give some precision about what the line in the release notes is about?
I can implement the workaround to store the “hosted-floating” key somewhere else, but as the original poster noted, this makes using floats rather cumbersome.
DeactivateLicense() function doesn’t reset the license key in case of hosted-floating license type given the perimission flag of SetProductId() is set to LA_IN_USER.
It seems you have passed LA_IN_MEMORY as a permission flag to SetProductId() which stores activation data only in the memory. So, in order to avoid that use LA_IN_USER
Thanks for the reply. I actually use LA_USER when calling SetProductId. On my previous tests I concluded that the licence information was deleted when calling DeactivateLicence() because the next IsLicenseGenuine() would fail with LA_FAIL. It turns out this is wrong; the license information is still there, however a call to ActivateLicense() is necessary on the next program start. This isn’t mentioned in the documentation.
Unfortunately, there are still remaining issues:
On program close, I use GetLicenseType to check if it’s a hosted floating license and decide whether DecactivateLicence() should be called (the program must also support node locked licenses). Unfortunately I can’t use GetLicenseType on program start to decide whether ActivateLicense() should be called because the call doesn’t work before the license is activated (even tough the information is probably somewhere on the disk). I can work around it by storing separately on the first activation whether it’s a floating licence, but the redundant storage of data of the license is not ideal and the reason the first question in this thread was started.
More importantly, when I start 2 instances on machine 1, and then stop one of them, the license is deactivated. I can then start the software on machine 2 with the same key; which is not what I want since an instance is already running on machine 1. The instance on machine 1 will then be killed after an hour by the SetLicenseCallback function (regardless if you stared an instance on another machine or not).
The sensible behaviour is to prevent starting another instance on machine 2 as long as one instance runs on machine 1 and not kill any other instances on machine 1 when you quit one instance.
I could work around that problem by calling ActivateLicense() only when the first instance on the machine starts and DeactivateLicense() only when the last instance last of that machine stops. Because LexActivator already has ways to know if other instances are running for other use cases, it seems strange to need to do that manally. I would expect LexActivator to do it for me, or at least document the behaviour.
I find the documentation for hosted floating licenses lacking. Is there some other documentation at another place that I missed? It looks like the sample code linked from the hosted floating license page doesn’t actually handle floating licenses.
Any guidance on how to properly implement hosted floating licenses is appreciated.
On program start, you should first call IsLicenseGenuine() function always, if it returns LA_FAIL only then you should call ActivateLicense() function. This will fix you GetLicenseType function issue on program start.
LexActivator provides you functions to code your behaviour, it doesn’t make any assumptions. If you call DeactivateLicense() from instance 1, it has to honour it, even if another instance is running on the same machine.
I agree the documentation is sparse. We have a pending ticket to add more examples for different use cases including floating, offline etc.
Till we update our examples, I would recommend the following flow:
SetProductData()
SetProductId()
if (IsLicenseGenuine() == LA_FAIL) {
if(GetLicenseKey() == "") {
// ask for license key
SetLicenseKey();
}
status = ActivateLicense()
}
...
if (GetLicenseType() == "hosted-floating")) {
DeactivateLicense(); //It invalidates the local data (except license key)
}
Thanks for the advices. I’ll follow the startup logic implementation and report back if I see issues.
For the second point I’m still usure what to do (eg. how to handle DeactivateLicense() with multiple instances on the same machine). It looks like I need a way to detect if there are other instances running. Doing that in a reliable and race condition free way with the DeactivateLicense() call is what is not completely straightforward.
To avoid implementing unecessary things here are a few questions:
Is LexActivator doing anything diffently in between a “Hosted Floating” licence with “Per-Machine” leasing strategy vs. “Per-Instance” leasing strategy?
If no and it needs to be implemented manually, what call in LexActivator.h can I use to I get the information if the license is per machine or per instance?
If yes, there must be a instance detection embedded inside LexActivator. Would it be possible to expose it?
I would find it useful to have a RequestFloatingLicense() and DropFloatingLicense() call like for the on-premise floating licence. The application would just need to call these on startup and exit and LexActivator would handle all the implementation details to work correctly depending the leasing strategy.
In the case of per-instance strategy, each instance of your app consumes a separate activation (even if they are running on the same machine) and you also need to use LA_IN_MEMORY) flag in this case.
You will face the same issue in case RequestFloatingLicense() and DropFloatingLicense() if you use per-machine floating strategy. Per instance strategy doesn’t suffer from this issue but may not be suitable for your use case.
You need to handle detection of multiple instances yourself. I gues you are using QT framework, I guess it provides some cross platform support for inter process communication which can help you with this.
I opted to implement a manual deactivate for floating licences (instead of automatically deactivate at the exit of the last instance), as it turned out to be pretty hard to reliably count the instances.
I also hoped this would be more robust to short outages of the internet. With an automatic deactivate, borrowing as described in the manual wouldn’t be possible, as the activate on the next start would need internet.
Borrowing floating licenses
Borrowing floating licenses for offline usage is supported out of the box. You just need to increase the leaseDuration to the amount of time you wish to lease the license for offline usage.
When having a borrowed licence (eg. before lease duration expired) while the machine is offline, a callback registered by SetLicenseCallback is being called straight away with a network error. I therefore opted to ignore network errors on the callback, otherwise it would exit the instance right after the start when being offline. On the next sync callbacks, when the lease duration has expired, the callback is just giving the same network error. The lincence will therefore run indefintely long when offline (going back online will detect that the licence expired and exit).
I can’t easily handle that case myself as I don’t want to make any hardcoded assumption about lease duration. I would expect LexActivator to call the callback function with a distinct error code to know that the lease expired and the activation couldn’t be renewed when offline.
Any suggestions on how to handle offline situations correctly in the callback?
I have another question about IsLicenseGenuine. Documentation says that it starts the background thread to do the sync and call the callback. I couldn’t find following info in the documentation:
When IsLicenseGenuine returns something different than LA_OK, is the background thread still started?
Is it safe to call IsLicenseGenuine multiple times, or will this start multiple background threads for sync?