I am trying to create a notification to be triggered on a schedule. I want the notification to show once a day around a set time (doesn't have to be exact). So what I'm trying to do is create a PeriodicWorkRequest that runs every 24 hours, and delay the start of the work request to the time of day I want it to run. I can get it running on a schedule, but whenever I create it, it just runs right away. I found some questions saying you can use .setInitialDelay() on the builder, however this doesn't seem to be available in the Xamarin Work Manager API. I have also tried .SetPeriodStartTime() on the Builder class after finding the method in the builder class definition, but this doesn't seem to be affecting anything.
MessagingCenter.Subscribe<StartNotificationRemindersMessage>(this, "StartNotificationRemindersMessage", message => {
TimeSpan startDelay = DateTime.Now.AddMinutes(2) - DateTime.Now;
PeriodicWorkRequest notificationsWorkRequest = PeriodicWorkRequest.Builder.From<NotificationsWorker>(1, TimeUnit.Days).SetPeriodStartTime(startDelay).Build();
WorkManager.Instance.Enqueue(notificationsWorkRequest);
});
Here I'm creating the periodic work request and trying to add a 2 minute delay to the start.
And here is the NotificationsWorker class.
class NotificationsWorker : Worker
{
public NotificationsWorker(Context context, WorkerParameters workerParameters) : base(context, workerParameters)
{
}
public override Result DoWork()
{
CrossLocalNotifications.Current.Show("GCS Reminder", "Testing reminder notifications");
return Result.InvokeSuccess();
}
}
If someone can show me what I'm doing wrong, it would be much appreciated.
Thanks!
There is an extension method named SetPeriodStartTime. It's extremely hard to find any documentation on it, but I've been experimenting with it and it appears to do the trick.
E.g.
PeriodicWorkRequest workRequest = PeriodicWorkRequest.Builder
.From<YourWorkerClass>(repeatInterval, flexInterval)
.SetPeriodStartTime(TimeSpan.FromHours(1))
.Build();
setInitialDelay() is now available on the builder in the Xamarin Work Manager API for Xamarin Android
I use setInitialDelay() to make sure PeriodicWorkRequest is delayed for a while you get a WorkRequest so Just cast it to a PeriodicWorkRequest
PeriodicWorkRequest notificationsWorkRequest = (PeriodicWorkRequest)PeriodicWorkRequest.Builder.From<YourWorkerClass>(repeatInterval,repeatIntervalTimeUnit).SetInitialDelay(repeatInterval,repeatIntervalTimeUnit).Build();
WorkManager.GetInstance(Android.App.Application.Context).Enqueue(notificationsWorkRequest );
Then to use it in Xamarin.Forms I use a dependency service, messaging center, or I just define it in the Android Main activity class depending on my reason for using work manager
example would be
PeriodicWorkRequest notificationsWorkRequest = (PeriodicWorkRequest) PeriodicWorkRequest.Builder.From<NotificationsWorker>(24, Java.Util.Concurrent.TimeUnit.Hours).SetInitialDelay(24, Java.Util.Concurrent.TimeUnit.Hours).Build();
Related
Over the last couple of years, I have done a fair amount of work on Amazon SWF, but the following points are still unclear to me and I am not able to find any straight forward answers on any forums yet.
These are pretty basic requirements I suppose, sure others might have come across too. Would be great if someone can clarify these.
Is there a simple way to return a workflow execution result (maybe just something as simple as boolean) back to workflow starter?
Is there a way to catch Activity timeout exception, so that we can do run customised actions in such scenarios?
Why doesn't WorkflowExecutionHistory contains Activities, why just Events?
Why there is no simple way of restarting a workflow from the point it failed?
I am considering to use SWF for more business processes at my workplace, but these limitations/doubts are holding me back!
FINAL WORKING SOLUTION
public class ReturnResultActivityImpl implements ReturnResultActivity {
SettableFuture future;
public ReturnResultActivityImpl() {
}
public ReturnResultActivityImpl(SettableFuture future) {
this.future = future;
}
public void returnResult(WorkflowResult workflowResult) {
System.out.print("Marking future as Completed");
future.set(workflowResult);
}
}
public class WorkflowResult {
public WorkflowResult(boolean s, String n) {
this.success = s;
this.note = n;
}
private boolean success;
private String note;
}
public class WorkflowStarter {
#Autowired
ReturnResultActivityClient returnResultActivityClient;
#Autowired
DummyWorkflowClientExternalFactory dummyWorkflowClientExternalFactory;
#Autowired
AmazonSimpleWorkflowClient swfClient;
String domain = "test-domain;
boolean isRegister = true;
int days = 7;
int terminationTimeoutSeconds = 5000;
int threadPollCount = 2;
int taskExecutorThreadCount = 4;
public String testWorkflow() throws Exception {
SettableFuture<WorkflowResult> workflowResultFuture = SettableFuture.create();
String taskListName = "testTaskList-" + RandomStringUtils.randomAlphabetic(8);
ReturnResultActivity activity = new ReturnResultActivityImpl(workflowResultFuture);
SpringActivityWorker activityWorker = buildReturnResultActivityWorker(taskListName, Arrays.asList(activity));
DummyWorkflowClientExternalFactory factory = new DummyWorkflowClientExternalFactoryImpl(swfClient, domain);
factory.getClient().doSomething(taskListName)
WorkflowResult result = workflowResultSettableFuture.get(20, TimeUnit.SECONDS);
return "Call result note - " + result.getNote();
}
public SpringActivityWorker buildReturnResultActivityWorker(String taskListName, List activityImplementations)
throws Exception {
return setupActivityWorker(swfClient, domain, taskListName, isRegister, days, activityImplementations,
terminationTimeoutSeconds, threadPollCount, taskExecutorThreadCount);
}
}
public class Workflow {
#Autowired
private DummyActivityClient dummyActivityClient;
#Autowired
private ReturnResultActivityClient returnResultActivityClient;
#Override
public void doSomething(final String resultActivityTaskListName) {
Promise<Void> activityPromise = dummyActivityClient.dummyActivity();
returnResult(resultActivityTaskListName, activityPromise);
}
#Asynchronous
private void returnResult(final String taskListname, Promise waitFor) {
ActivitySchedulingOptions schedulingOptions = new ActivitySchedulingOptions();
schedulingOptions.setTaskList(taskListname);
WorkflowResult result = new WorkflowResult(true,"All successful");
returnResultActivityClient.returnResult(result, schedulingOptions);
}
}
The standard pattern is to host a special activity in the workflow starter process that is used to deliver the result. Use a process specific task list to make sure that it is routed to a correct instance of the starter. Here are the steps to implement it:
Define an activity to receive the result. For example "returnResultActivity". Make this activity implementation to complete the Future passed to its constructor upon execution.
When the workflow is started it receives "resultActivityTaskList" as an input argument. At the end the workflow calls this activity with a workflow result. The activity is scheduled on the passed task list.
The workflow starter creates an ActivityWorker and an instance of a Future. Then it creates an instance of "returnResultActivity" with that future as a constructor parameter.
Then it registers the activity instance with the activity worker and configures it to poll on a randomly generated task list name. Then it calls "start workflow execution" passing the generated task list name as an input argument.
Then it wait on the Future to complete. The future.get() is going to return the workflow result.
Yes, if you are using the AWS Flow Framework a timeout exception is thrown when activity is timed out. If you are not using the Flow framework than you are making your life 100 times harder. BTW the workflow timeout is thrown into a parent workflow as a timeout exception as well. It is not possible to catch a workflow timeout exception from within the timing out instance itself. In this case it is recommended to not rely on workflow timeout, but just create a timer that would fire and notify workflow logic that some business event has timed out.
Because a single activity execution has multiple events associated to it. It should be pretty easy to write code that converts history to whatever representation of activities you like. Such code would just match the events that relate to each activities. Each event always has a reference to the related events, so it is easy to roll them up into higher level representation.
Unfortunately there is no easy answer to this one. Ideally SWF would support restarting workflow by copying its history up to the failure point. But it is not supported. I personally believe that workflow should be written in a way that it never fails but always deals with failures without failing. Obviously it doesn't work in case of failures due to unexpected conditions. In this case writing workflow in a way that it can be restarted from the beginning is the simplest approach.
Somewhere in my Vaadin application, I'm getting this exception as soon as I connect using a second browser
Caused by: java.lang.RuntimeException: A connector with id 22 is already registered!
at com.vaadin.ui.ConnectorTracker.registerConnector(ConnectorTracker.java:133)
It happens always in the same place but I don't know why exactly as the reason for this must be somewhere else.
I think I might be stealing UI components from the other session - which is not my intention.
Currently, I don't see any static instances of UI components I might be using in multiple sessions.
How can I debug this? It's become quite a large project.
Any hints to look for?
Yes, this usually happens because you are attaching a component already attached in other session.
Try logging the failed connector with a temporal ConnectorTracker, So the next time that it happens, you can catch it.
For example:
public class SomeUI extends UI {
private ConnectorTracker tracker;
#Override
public ConnectorTracker getConnectorTracker() {
if (this.tracker == null) {
this.tracker = new ConnectorTracker(this) {
#Override
public void registerConnector(ClientConnector connector) {
try {
super.registerConnector(connector);
} catch (RuntimeException e) {
getLogger().log(Level.SEVERE, "Failed connector: {0}", connector.getClass().getSimpleName());
throw e;
}
}
};
}
return tracker;
}
}
I think I might be stealing UI components from the other session - which is not my intention. Currently, I don't see any static instances of UI components I might be using in multiple sessions.
That was it. I was actually stealing UI components without prior knowledge.
It was very well hidden in a part which seems to be same for all instances. Which is true: the algorithm is the same.
Doesn't mean I should've reused the same UI components as well...
Thanks to those who took a closer look.
Here is how I fixed it -
1) look for components you have shared across sessions. For example if you have declared a component as static it will be created once and will be shared.
2) if you are not able to find it and want a work around until you figure out the real problem, put your all addComponent calls in try and in catch add following code -
getUI().getConnectorTracker().markAllConnectorsDirty();
getUI().getConnectorTracker().markAllClientSidesUnititialized();
getPage().reload():
This will clear old connectors and will reload the page properly only when it fails. For me it was failing when I was logged out and logged in back.
Once you find the real problem you can fix it till then inform your customers about the reload.
**** note - only solution is to remove shared components this is just a work around.
By running your application in debug mode (add ?debug at the end of URL in browser) you will be able to browse to the component, e.g:
-UIConnector(0)
--VerticalLayoutConnector(1)
---...
---LabelConnector(22)
where 22 is id from your stack trace. Find this component in your code and make sure that it is not static (yes, I saw such examples).
As far as I looked, there's no answered question about QTP's Ext. sdk on stackoverflow (and almost anywhere else on the net; there isn't even a appropriated tag for it...), so I'm aware it's unlikely I get my problem solved by asking , but whatever, it worth trying.
Anyway, before I lose the attention of anyone who never heard or used the Ext. sdk, maybe I will have more luck asking you to help me figure out how to locate the error log file QTP produces at run-time. I know such a file exists in the new UFT 11.5 version, but I couldn't locate it in QTP 10 or 11 (For the record, I don't talk about QTP's Log Tracking feature, but about the "meta" error log of errors/exceptions produced by QTP itself).
Now for the question:
I'm developing an extension for QTP to support native record and run tests on my application.
I'm currently able to import an object repository, and write test steps using The COM object testing agent I developed.
Problem started when I was trying to implement the IRecordable interface; I'm getting the IRecorder object from qtp, and even able to use it as ISuppressor object to exclude redundant steps from being recorded, but all my attempts to record a step (that is, to add new recorded objects to the repository, and add steps to the test) simply failed.
This is the code that I'm using:
public class MyTestingAgent :
AutInterface.ITestable,
AutInterface.IRecordable
{
QTPInterface.IRecorder recorder;
...
public void AutInterface.IRecordable.BeginRecording(object recorder)
{
IRecordSuppressor recordSuppressor = recorder as IRecordSuppressor;
recordSuppressor.Suppress(MyTestingAgentId,
"<Suppress><Item type=\"HWND\" value=\"[#HWND]\" /></Suppress>".Replace("[#HWND]", getMyAppHWND().ToString()));
this.recorder = recorder as QTPInterface.IRecorder;
...
}
public void recordNewObjStep(string parentName, string objName, string method, Object[] arguments)
{
object[] objectHyrarchy = new object[] { findObjectId(objName), findObjectId(parentName) };
string externalParent = null;
string appDescriptionXml = getDescriptionXml(parentName, objName);
try
{
recorder.Record(MyTestingAgentId, objectHyrarchy , appDescriptionXml, externalParent, method, arguments);
Trace.TraceInformation("Record successfully done.");
}
catch (Exception e)
{
Trace.TraceError("TEAAgent.recordSTElement: " + e.ToString());
}
}
...
}
I'm pretty sure all the arguments I send with the call to Record() are accurate. getDescriptionXml() and findObjectId() are used in different cases in the code, and works fine, the method name and argument are correct.
The annoying thing is that the call to Record doesn't even throw exception, and I get "Record successfully done." in the trace log. Needless to say no new object is created in the repository, and no step is added to the test.
As I can't debug QTP, I'm pretty much in the dark with what I'm doing wrong. That's why I'm asking for help with finding QTP's log file, or any other approach that might shed some light on the subject.
For QTP 11 you can turn on the logs by going to QTP's bin directory and running ClientLogs.exe.
Specifically for TEA extensibility do the following.
select the QTP node from the list on the left
find the LogCatPackTEA from the Available Categories list
Click the > button to move it to Selected Categories
Change TEAs level to Debug2 by selecting the category and changing the level
Click OK and run QTP
The logs will show up as QTP.log in the diretory specified in Path:
I'm curious on what the problem you're facing is, please update if you find the cause.
I'm evaluating Amazon SWF as an option to build a distributed workflow system. The main language will be Java, so the Flow framework is an obvious choice. There's just one thing that keeps puzzling me and I would get some other opinions before I can recommend it as a key component in our architecture:
The examples are all about tasks that produce a result after a deterministic, relatively short period of time (i.e. after some minutes). In our real-life business workflow, the matter looks different, here we have tasks that could take potentially weeks to complete. I checked the calculator already, having workflows that live 30 days or so do not lead to a cost explosion, so it seems they already counted in that possibility.
Did anybody use SWF for some scenario like this and can share any experience? Are there any recommendations, best practices how to design a workflow like this? Is Flow the right choice here?
It seems to me Activity implementations are expected to eventually return a value synchronously, however, for long running transactions we would rather use messages to send back worker results asynchronously.
Any helpful feedback is appreciated.
From the Amazon Simple Workflow Service point of view an activity execution is a pair of API calls: PollForActivityTask and RespondActivityTaskCompleted that share a task token. There is no requirement for those calls coming from the same thread, process or even host.
By default AWS Flow Framework executes an activity synchronously. Use #ManualActivityCompletion annotation to indicate that activity is not complete upon return of the activity method. Such activity should be explicitly completed (or failed) using provided ManualActivityCompletionClient.
Here is an example taken from the AWS Flow Framework Developer Guide:
#ManualActivityCompletion
public String getName() {
ActivityExecutionContext executionContext = contextProvider.getActivityExecutionContext();
String taskToken = executionContext.getTaskToken();
sendEmail("abc#xyz.com",
"Please provide a name for the greeting message and close task with token: " + taskToken);
return "This will not be returned to the caller";
}
public class CompleteActivityTask {
public void completeGetNameActivity(String taskToken) {
AmazonSimpleWorkflow swfClient = new AmazonSimpleWorkflowClient(…); //pass in user credentials
ManualActivityCompletionClientFactory manualCompletionClientFactory = new ManualActivityCompletionClientFactoryImpl(swfClient);
ManualActivityCompletionClient manualCompletionClient
= manualCompletionClientFactory.getClient(taskToken);
String result = "Hello World!";
manualCompletionClient.complete(result);
}
public void failGetNameActivity(String taskToken, Throwable failure) {
AmazonSimpleWorkflow swfClient
= new AmazonSimpleWorkflowClient(…); //pass in user credentials
ManualActivityCompletionClientFactory manualCompletionClientFactory
= new ManualActivityCompletionClientFactoryImpl(swfClient);
ManualActivityCompletionClient manualCompletionClient
= manualCompletionClientFactory.getClient(taskToken);
manualCompletionClient.fail(failure);
}
}
That an activity is implemented using #ManualActivityCompletion is an implementation detail. Workflow code calls it through the same interface and doesn't treat any differently than any activity implemented synchronously.
OK, I'm trying to set a property on a type I'm registering with SM.
Here's the code from the registry in one of my components. This
registry is being added during the configuration from a console app.
When I try to access the EndorsementSpecs property of the instance
AutoMandatoryEndorsementAggregator object, I get the 202. What's
interesting is that I can call
GetAllInstances>() from my
console app and it resolves just fine. Is there something about
accessing this code from within OnCreation that is causing the 202? I
can see everything I expect in WhatDoIHave(). I've also tried a TypeInterceptor with the same results.
//register all open generics
cfg.ConnectImplementationsToTypesClosing(typeof
(MandatoryEndorsementSpecBase<>));
ForSingletonOf<IMandatoryEndorsementAggregator<AutoPolicy>>()
.Use<AutoMandatoryEndorsementAggregator>()
.OnCreation((context, x) =>
{
var specs =
context.GetAllInstances<MandatoryEndorsementSpecBase<AutoPolicy>>();
x.EndorsementSpecs = specs;
})
;
Sorry to deflect your real questions, but are you just trying to inject all instances of MandatoryEndorsementSpecBase into AutoMandatoryEndorsementAggregatory?
If so, you can probably get away with just making it a constructor parameter so that they are all automatically injected.
public AutoMandatoryEndorsementAggregatory(MandatoryEndorsementSpecBase<AutoPolicy>[] endorsementSpecs){
EndorsementSpecs = endorsementSpecs;
}