Xamarin.Forms Sqlite (sometimes) fetching bad result after update - sqlite

I have a Xamarin.Forms project which uses a local database file Sqlite (the file is called datas.lite) from sqlite-net-pcl nuget package (version 1.2.0).
I have a table called Item:
public class Item
{
[PrimaryKey]
public int ID { get; set; }
public bool IsActive { get; set; }
}
And a repository ItemRepository with a static connection SQLite, I use to update the Item rows:
public class ItemRepository
{
private static SQLite.SQLiteConnection _conn;
private static SQLite.SQLiteConnection Conn
{
get
{
if (_conn == null)
_conn = new SQLite.SQLiteConnection("myPath/datas.lite");
return _conn
}
}
public ItemRepository()
{
Conn.CreateTable<Item>();
}
public Item GetById(int id)
{
return Conn.Get<Item>(id);
}
// Retrieves all items from table Item
public IEnumerable<Item> GetAll()
{
return Conn.Table<Item>();
}
// Updates the provided item
public int InsertOrReplace(Item item)
{
return Conn.InsertOrReplace(item, typeof(Item));
}
}
The app modifies the IsActive property for all items every 5 minutes by updating the Item table (The method TimerHelper.StartTimerInNewThread is called once at startup).
TimerHelper.StartTimerInNewThread(TimeSpan.FromSeconds(delais), ()
=>
{
try
{
// retrieve all items with DB
List<Item> items = repo.GetAll();
foreach (Item item in items)
{
item.IsActive = !item.IsActive;
if (repo.InsertOrReplace(item) == 1)
{
Log?.Info($"Item {item} has been updated in DB: IsActive = {repo.GetItem(item).IsActive}.");
}
else
{
throw new Exception($"InsertOrReplace() method returned a value != 1.");
}
}
}
catch (Exception ex)
{
// Log exception here
}
});
And immediately after updating the rows of table Item, I check (I log every IsActive property value for every Item) that the IsActive property of all items actually changed. So far, so good.
But if I let the application runs for several hours, sometimes, the check does not reflect the previous update...for instance, the application set the IsActive property for all items to TRUE, but the immediate request to the IsActive property returns FALSE for all items.
If I read via DbBrowser for Sqlite the table Item from the database local file (datas.lite), every item has its IsActive property set to TRUE, which is correct. So why the immediate read request I made after the update returned FALSE for all items, is there any caching that is active with sqlite? Or is it due to the fact that I have a static connection, and it is never closed, (it is moreover the recommanded way of doing according to microsoft documentation: https://learn.microsoft.com/en-us/xamarin/get-started/quickstarts/database?pivots=windows)
Thank you for any help

Here is how to protect timer code from being re-entered while it is still running.
Compare these three ways of running code repeatedly using a timer.
This is "typical" timer code. "seconds" is the time interval at which the work is done. Works fine if the code always finishes before the timer delay fires it again. Problematic if the timer code might take the ENTIRE time interval. (or if some background work, such as GC, takes enough time that your timer code eats the remaining time.) Really problematic if timer code takes so long that timer events start "piling up", starving the rest of your app from getting any time.
TYPICAL "NAIVE" TIMER CODE:
// Works fine if action is shorter than time delay.
// DON'T USE THIS CODE, if action might take longer than time delay.
using Timer = System.Timers.Timer;
private void StartFixedDelayTimer(float seconds, Action action)
{
_timer = new Timer(1000 * seconds);
_timer.Elapsed += (sender, e) => action();
// The timer event repeats until explicitly stopped.
_timer.Start();
}
SKIP-IF-BUSY TIMER CODE:
This is similar, but it protects itself by "skipping" work, if the work is still being done:
// For long running "action", increase "idleSeconds" to guarantee more time for other background tasks.
private void StartFixedDelayTimerSkipIfBusy(float seconds, Action action, float idleSeconds = 0.1f)
{
_timer = new Timer(1000 * seconds);
bool entered = false;
_timer.Elapsed += (sender, e) => {
if (entered)
// Timer code already running! Skip this one.
return;
entered = true;
try {
action();
// IMPORTANT: This is needed to "see and skip" next timer event,
// if it happens during "action". Without this, timer events can "pile up",
// starving other background tasks.
System.Threading.Thread.Sleep((int)(1000 * idleSeconds));
} finally {
entered = false;
}
};
// The timer event repeats until explicitly stopped.
_timer.Start();
}
VARIABLE-DELAY TIMER CODE:
This is an alternative approach. It doesn't request that the work be done again, until AFTER it finishes the first time. Here "seconds" is the amount of time between FINISHING the work, and the start of the next work. This is useful if you don't need the work done on a rigorous clock schedule. It has the advantage that no matter how long "action" takes, the rest of your app code gets "seconds" of cpu time before this work starts again - won't "starve" your app.
private void StartDelayBetweenWorkTimer(float seconds, Action action)
{
_timer = new Timer(1000 * seconds);
// Only fire the timer once. (But in Elapsed, we fire it again.)
_timer.AutoReset = false;
_timer.Elapsed += (sender, e) => {
action();
// Fire the timer again. Work will be done again "seconds" seconds after this statement is called.
_timer.Start();
};
_timer.Start();
}

Related

JavaFX Task updateValue throws IllegalStateException: Not on FX application thread

I have a simple application with a single JavaFX window. I'm sending in data to an Azure IoTHub inside a for loop. This for loop is in a JavaFX Task, and the for loop has a small delay (Thread.sleep(300)) so progress can be shown on the UI. I have 2 labels I want to update during the data transmission, always showing the latest sent in data. I have the following helper class for this:
public class DataHelper {
private StringProperty date = new SimpleStringProperty();
private StringProperty count = new SimpleStringProperty();
public DataHelper() {
}
public DataHelper(String date, String count) {
this.date.setValue(date);
this.count.setValue(count);
}
//getters and setters
}
And here is my sendErrorsToHub method inside my UI controller class:
private void sendErrorsToHub(List<TruckErrorForCloud> toCloud) {
DataHelper dataHelper = new DataHelper("", "");
Task task = new Task<DataHelper>() {
#Override
public DataHelper call() {
try {
int i = 0;
for (TruckErrorForCloud error : toCloud) {
Thread.sleep(300);
i++;
String strMessage = Utility.toPrettyJson(null, error);
if (strMessage != null) {
Message msg = new Message(strMessage);
msg.setMessageId(java.util.UUID.randomUUID().toString());
client.sendEventAsync(msg, null, null);
}
updateProgress(i, toCloud.size());
DataHelper dh = new DataHelper(error.getErrorTimeStamp().substring(0, error.getErrorTimeStamp().length() - 9),
String.valueOf(error.getCount()));
updateValue(dh);
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
#Override
protected void updateValue(DataHelper value) {
super.updateValue(value);
dataHelper.setDate(value.getDate());
dataHelper.setCount(value.getCount());
}
//succeeded method omitted
};
dateValue.textProperty().bind(dataHelper.dateProperty());
countValue.textProperty().bind(dataHelper.countProperty());
progressBar.progressProperty().bind(task.progressProperty());
new Thread(task).start();
}
When I run the application, I constantly get IllegalStateException: Not on FX application threadexceptions, inside the updateValue method. As far as I understand the documentation, the whole point of the updateValue method, that it runs on the Application thread, and it can be used to pass a custom object, which can be used to update the UI.
What am I doing wrong then?
The bottom of the stacktrace with my classes is the following:
at eu.mantis.still_rca_simulator.gui.DataHelper.setDate(DataHelper.java:28)
at eu.mantis.still_rca_simulator.gui.GuiController$1.updateValue(GuiController.java:166)
at eu.mantis.still_rca_simulator.gui.GuiController$1.call(GuiController.java:155)
at eu.mantis.still_rca_simulator.gui.GuiController$1.call(GuiController.java:138)
(138 is the line Task task = new Task(), 155 updateValue(dh);, 166 dataHelper.setDate(value.getDate());)
updateValue does not automatically run on the application thread and it's not necessary to run it on the application thread since it takes care of updating the value property of Task on the application thread.
Your code in the overridden version updateValue executes logic on the background thread that needs to be run on the application thread though:
dataHelper.setDate(value.getDate());
dataHelper.setCount(value.getCount());
The bindings result in the text properties being updated from the background thread since the above code runs on the background thread.
In this case I recommend using a immutable DataHelper class and updating the ui using a listener to the value property:
Remove the updateValue override and the dataHelper local variable, initialize the gui with empty strings, if necessary, declare task as Task<DataHelper> task and do the following to update the gui:
task.valueProperty().addListener((o, oldValue, newValue) -> {
if (newValue != null) {
dateValue.setText(newValue.getDate());
countValue.setText(newValue.getCount());
}
});
You may also use Platform.runLater for those updates, since they don't happen frequently enough to result in issues that could be the result of using Platform.runLater too frequently.

Application Insights Telemetry filtering is not working

I have already followed the guide here. I have tried both the config and "in code" approach of initializing and registering our telemetry processor. My goal is to filter out some HTTP responses so that those don't make their way to the sampled data. I haven't had any success. While our processor is initialized on app start, the Process method is never hit. Also, I already made sure that there is an InstrumentationKey in the config and that I'm using the correct key. What else am I missing?
This is what I have:
public class MyTelemetryProcessor : ITelemetryProcessor
{
private ITelemetryProcessor Next { get; set; }
// You can pass values from .config
public string MyParamFromConfigFile { get; set; }
// Link processors to each other in a chain.
public MyTelemetryProcessor(ITelemetryProcessor next)
{
this.Next = next; <-- this is always hit indicating this processor is active
}
public void Process(ITelemetry item)
{
// To filter out an item, just return
if (!OKtoSend(item)) { return; } <-- breakpoint here is never hit
// Modify the item if required
ModifyItem(item);
this.Next.Process(item);
}
private bool OKtoSend(ITelemetry item) <-- and consequently this method is never hit
{
var request = item as RequestTelemetry; <-- breakpoint here is never hit
// some more code goes here
return request.Success.GetValueOrDefault(false);
}
// Example: replace with your own modifiers.
private void ModifyItem(ITelemetry item)
{
item.Context.Properties.Add("app-version", "1." + MyParamFromConfigFile);
}
}
And this is how it is registered. I can see this being hit during debugging when the app starts up:
var builder = TelemetryConfiguration.Active.TelemetryProcessorChainBuilder;
builder.Use((next) => new MyTelemetryProcessor (next));
builder.Build();
In aspnetcore, my solution was to use :
services.AddApplicationInsightsTelemetryProcessor(typeof(BasicTelemetryFilter));
(using the regular CreateWebHostBuilder :
WebHost.CreateDefaultBuilder(args)
.UseApplicationInsights()
.UseStartup<Startup>();
)

Set up an actitivity that will blocked until a new element insert into my database

I'm new in workflows C #, I want to set up an activity that will be blocked until a new element insert into my database , after I pass to another activity.
From your question I believe you are asking for a way to stop the workflow proceeding until you get a database entry and if you do to continue the workflow.
And if you do not get the entry to not continue the workflow.
This answer uses the Flowchart model of workflows.
A way to do this is to write an Code Activity (also called Custom Activity) that reads your database and determines if the entry has arrived and then sets a bool Out Argument of the activity. This bool should set a Variable in the workflow.
Then after that you add a FlowDecision activity to read the bool Variable.
If true you continue the workflow
If false you add a loop back to your database reading activity.
This solution leaves the workflow running in memory.
There are more sophisticated solutions but as you are new to workflows I have given the most simple.
public sealed class Controller: CodeActivity
{
public OutArgument<String> Item { get; set; }
CodeActivityContext con;
public SqlTableDependency<VacationRequest> _dependency;
private void _dependency_OnChanged(object sender, TableDependency.EventArgs.RecordChangedEventArgs<VacationRequest> even)
{
if (even.ChangeType != ChangeType.None)
{
switch (even.ChangeType)
{
case ChangeType.Update:
try
{
Item.Set(con, "yeééés");// ****Exception
Console.WriteLine("iiiiiiiiiiiiiiii");
//_dependency.Stop();
break;
}
catch (Exception)
{
con.SetValue(Item, "tttt");
break;
}
}
}
}
protected override void Execute(CodeActivityContext context)
{
con = context;
_dependency = new SqlTableDependency<VacationRequest>(ConfigurationManager.ConnectionStrings["DbContext"].ConnectionString, "VacationRequests");
_dependency.OnChanged += _dependency_OnChanged;
_dependency.Start();
//context.SetValue(Item, "test");
}
}

SysOperation Framework suppress infolog messages for ReliableAsynchronous but keep them in batch history

I'm just getting my feet wet with the SysOperation framework and I have some ReliableAsynchronous processes that run and call info("starting...") etc.
I want these infolog messages so that when I look in the BatchHistory, I can see them for purposes of investigating later.
But they also launch to the client, from the batch. And I can tell they're from the batch because you can't double click on the infologs to go to the source. Is there someway to either suppress these from popping up on the user's screen and only show in the batch log?
EDIT with some code:
User clicks a button on form action pane that calls an action menu item referencing a class.
In the class, the new method:
public void new()
{
super();
this.parmClassName(classStr(MyControllerClass));
this.parmMethodName(methodStr(MyControllerClass, pickTransLines));
this.parmExecutionMode(SysOperationExecutionMode::ReliableAsynchronous);
// This is meant to be running as a batch task, so don't load syslastvalue
this.parmLoadFromSysLastValue(false);
}
The main method hit from the menu item:
public static void main (Args _args)
{
MyControllerClass controller = new MyControllerClass();
MyContract contract;
WMSOrderTrans wmsOrderTrans;
RefRecId refRecId;
if (_args && _args.dataset() == tableNum(WMSOrderTrans) && _args.record())
{
contract = controller.getDataContractObject();
contract.parmRefRecId(_args.record().RecId);
controller.parmShowDialog(false);
refRecId = controller.doBatch().BatchJobId;
// This creates a batch tracking record
controller.updateCreateTracking(refRecId, _args.record().RecId);
}
}
The controller method that gets launched:
// Main picking method
private void pickTransLines(MyContract_contract)
{
MyTrackingTable tracking;
boolean finished;
BatchHeader batchHeader = BatchHeader::getCurrentBatchHeader();
boolean updateTracking = false;
// NOTE - This infolog launches after a few seconds to the user, but
// you can't double click on the info message to go to the code
// because it's fired from the batch somehow.
info(strFmt("Working on wmsordertrans.recid == %1", _contract.parmRefRecId()));
// Create/Update batch tracker if needed
if (this.isInBatch())
{
// NOTE - This code gets executed so we ARE in batch
this.updateTrackingStuff(...);
}
// Do the pick work
finished = this.doPick(_contract);
if(!finished)
throw error("An error occurred during the picking process.");
}
Then a split second later this launches to my session:
Look at the SysOperationServiceController.afterOperation method,:
[...]
if (_executionMode == SysOperationExecutionMode::ReliableAsynchronous)
{
batch = this.operationReturnValue();
if (batch)
{
infolog.view(Batch::showLog(batch.RecId));
}
}
[...]
This is the code that shows the infolog to the screen for reliable asynchronous processed.
You can create your own controller by extending SysOperationServiceController and use that on your menu item or in code, so do that and overwrite the afterOperation on your new controller, for example like this (didn't test but should work in your case):
if (_executionMode != SysOperationExecutionMode::ReliableAsynchronous)
{
super(_executionMode, _asyncResult);
}

Synchronous responses to `Gdx.net.sendHttpRequest` in LibGDX

I'm making a small game in LibGDX. I'm saving the player's username locally as well as on a server. The problem is that the application is not waiting for the result of the call so the online database's ID is not saved locally. Here's the overall flow of the code:
//Create a new user object
User user = new User(name);
//Store the user in the online database
NetworkService networkService = new NetworkService();
String id = networkService.saveUser(user);
//Set the newly generated dbase ID on the local object
user.setId(id);
//Store the user locally
game.getUserService().persist(user);
in this code, the id variable is not getting set because the saveUser function is returning immediately. How can I make the application wait for the result of the network request so I can work with results from the server communication?
This is the code for saveUser:
public String saveUser(User user) {
Map<String, String> parameters = new HashMap<String, String>();
parameters.put("action", "save_user");
parameters.put("json", user.toJSON());
HttpRequest httpGet = new HttpRequest(HttpMethods.POST);
httpGet.setUrl("http://localhost:8080/provisioner");
httpGet.setContent(HttpParametersUtils.convertHttpParameters(parameters));
WerewolfsResponseListener responseListener = new WerewolfsResponseListener();
Gdx.net.sendHttpRequest (httpGet, responseListener);
return responseListener.getLastResponse();
}
This is the WerewolfsResponseListener class:
class WerewolfsResponseListener implements HttpResponseListener {
private String lastResponse = "";
public void handleHttpResponse(HttpResponse httpResponse) {
System.out.println(httpResponse.getResultAsString());
this.lastResponse = httpResponse.getResultAsString();
}
public void failed(Throwable t) {
System.out.println("Saving user failed: "+t.getMessage());
this.lastResponse = null;
}
public String getLastResponse() {
return lastResponse;
}
}
The asynchrony you are seeing is from Gdx.net.sendHttpRequest. The methods on the second parameter (your WerewolfsResponseListener) will be invoked whenever the request comes back. The success/failure methods will not be invoked "inline".
There are two basic approaches for dealing with callbacks structured like this: "polling" or "events".
With polling, your main game loop could "check" the responseListener to see if its succeeded or failed. (You would need to modify your current listener a bit to disambiguate the success case and the empty string.) Once you see a valid response, you can then do the user.setId() and such.
With "events" then you can just put the user.setId() call inside the responseListener callback, so it will be executed whenever the network responds. This is a bit more of a natural fit to the Libgdx net API. (It does mean your response listener will need a reference to the user object.)
It is not possible to "wait" inline for the network call to return. The Libgdx network API (correctly) assumes you do not want to block indefinitely in your render thread, so its not structured for that (the listener will be queued up as a Runnable, so the earliest it can run is on the next render call).
I would not recommend this to any human being, but if you need to test something in a quick and dirty fashion and absolutely must block, this will work. There's no timeout, so again, be prepared for absolute filth:
long wait = 10;
while(!listener.isDone())
{
Gdx.app.log("Net", "Waiting for response");
try
{
Thread.sleep(wait *= 2);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
public static class BlockingResponseListener implements HttpResponseListener
{
private String data;
private boolean done = false;
private boolean succeeded = false;
#Override
public void handleHttpResponse(HttpResponse httpResponse)
{
Gdx.app.log("Net", "response code was "+httpResponse.getStatus().getStatusCode());
data = httpResponse.getResultAsString();
succeeded = true;
done = true;
}
#Override
public void failed(Throwable t)
{
done = true;
succeeded = false;
Gdx.app.log("Net", "Failed due to exception ["+t.getMessage()+"]");
}
public boolean succeeded()
{
return succeeded;
}
public boolean isDone()
{
return done;
}
public String getData()
{
return data;
}
}

Resources