How to detect failure of task execution from a vscode extension? - visual-studio-code

My Visual Studio code extension allows users to deploy and debug applications on remote devices.
To do this I need to have the application "installed" in a local folder that will then be synchronized to the target using rsync.
Some languages/tools provide a simple and standardized way to do this (ex: dotnet publish, for .NET core apps), others don't.
To be flexible and let users choose the method they prefer, my extension relies on a task with a specific name to perform the operation.
I have a resolveDebugConfiguration function that executes the task and then fills out the information inside debug connection to let user debug his app.
As long as this is a single task, this is not an issue. I can start it using vscode.tasks.executeTask and wait for its completion using OnEndTaskProcess. The task should be shell/process and a non-zero exit code means failure. I also check OnEndTask, to be sure that I don't miss other kinds of completition (ex: an invalid path in the cmd field or the user defined a custom task etc.).
Some users may want to have a more complex structure for this. For example having their deployment tasks depend on a build task, to ensure that the latest version is deployed, or perform additional operations in between, so I no longer have a single task, but a chain of tasks connected via dependson.
This is ok and still works...until it fails.
Or, better, until one of the dependency tasks fail.
In this case, I have no notification from OnEndTaskProcess or even OnEndTask and the tasks after the failed one remain inside vscode.tasks.taskExecutions list forever, it seems.
So my resolveDebugConfiguration function never returns and vscode remains in the "starting debugger" state forever...
My code looks like this:
// retrieve task given its name
const tasks = await vscode.tasks.fetchTasks();
var deploy: vscode.Task | undefined = undefined;
for (var task of tasks) {
switch (task.name) {
case "deploy":
deploy = task;
break;
}
}
if (deploy === undefined) {
// error message telling user that he has to define a task named "deploy"
return null;
}
var emitter = new EventEmitter();
// the process event arrives before the generic terminate one (checked inside vscode sources)
vscode.tasks.onDidEndTaskProcess(e => {
if (e.execution.task.name === "deploy") {
emitter.emit("terminated", e.exitCode);
}
});
vscode.tasks.onDidEndTask(e => {
// check if task is still running, otherwise report an error
var taskexecutions = vscode.tasks.taskExecutions;
for (var taskexecution of taskexecutions) {
if (taskexecution.task.name === "deploy") {
return;
}
}
emitter.emit("terminated", -1);
});
try {
var execution = await vscode.tasks.executeTask(deploy);
}
catch (e) {
// catch execution exceptions and show a message to the user
return null;
}
var code = await new Promise<Number>((resolve, reject) => {
emitter.on("terminated", code => resolve(code));
});
if (code !== 0) {
// deploy task failed
return null;
}
// local deployment succeeded, move on...
Some of the tasks may take a long time, so using a timeout may be a solution worse than the problem.
It would be nice to have OnEndTask called even when a dependency fails, preventing the actual task from running, but this does not seem to happen.
I plan to open an issue on vscode github repo, but maybe someone has a solution that doesn't involves changes to the ide itself.

Related

How do I make data calls from different Blazor components simultaneously?

I'm new to Blazor and trying to make a page with several separate components to handle a massive form. Each individual component covers a part of the form.
The problem I'm facing is that each of my components needs access to data from the back-end, and not every component uses the same data. When the page loads, each components makes an attempt to fetch data from the server, which causes a problem with Entity Framework.
A second operation started on this context before a previous operation
completed. This is usually caused by different threads using the same
instance of DbContext.
This is obviously caused by the fact that my components are initialized at the same time, and all make their attempt to load the data simultaneously. I was under the impression that the way DI is set up in Blazor, this wouldn't be a problem, but it is.
Here are the components in my template:
<CascadingValue Value="this">
<!-- BASE DATA -->
<CharacterBaseDataView />
<!-- SPECIAL RULES -->
<CharacterSpecialRulesView />
</CascadingValue>
Here is how my components are initialized:
protected async override Task OnInitializedAsync()
{
CharacterDetailsContext = new EditContext(PlayerCharacter);
await LoadCharacterAsync();
}
private async Task LoadCharacterAsync()
{
PlayerCharacter = await PlayerCharacterService.GetPlayerCharacterAsync(ViewBase.CharacterId.Value);
CharacterDetailsContext = new EditContext(PlayerCharacter);
}
When two components with the above code are in the same view, the mentioned error occurs. I thread using the synchronous version "OnInitialized()" and simply discarding the task, but that didn't fix the error.
Is there some other way to call the data so that this issue doesn't occur? Or am I going about this the wrong way?
You've hit a common problem in using async operations in EF - two or more operations trying to use the same context at once.
Take a look at the MS Docs article about EF DBContexts - there's a section further down specific to Blazor. It explains the use of a DbContextFactory and CreateDbContext to create contexts for units-of-work i.e. one context per operation so two async operations each have a separate context.
Initially to solve the threading issues, I used DbContextFactory to create contexts for each operation - however this resulted in database in-consistency issues across components, and I realised I need change tracking across components.
Therefore instead, I keep my DbContext as scoped, and I don't create a new context before each operation.
I then adapted my OnInitializedAsync() methods to check if the calls to the database have completed, before making these calls through my injected services. This works really well for my app:
#code {
static Semaphore semaphore;
//code ommitted for brevity
protected override async Task OnInitializedAsync()
{
try
{
//First open global semaphore
semaphore = Semaphore.OpenExisting("GlobalSemaphore");
while (!semaphore.WaitOne(TimeSpan.FromTicks(1)))
{
await Task.Delay(TimeSpan.FromSeconds(1));
}
//If while loop is exited or skipped, previous service calls are completed.
ApplicationUsers = await ApplicationUserService.Get();
}
finally
{
try
{
semaphore.Release();
}
catch (Exception ex)
{
Console.WriteLine("ex.Message");
}
}
}

sails lowers without process.exit - feature or mistake?

My sails.js app is running under PM2, and I'd like PM2 to be able to restart the app, which it does in the case of a crash. The thing is, when sails fails to load a hook, for instance, if a DB is not available at startup, then the graceful sails.lower() is called internally by sails, but the actual node process does not exit (no process.exit() is called after the lowering) by the core sails code. This has the result of PM2 not knowing that sails has shutdown, and therefore not starting it back up again.
This all happens in the initial bootstrapping of the app, and is before any of my code is called, so I have no control over it.
Does anybody have any suggestions of how I may solve this?
I'm thinking I could write a custom core hook that could hook into the sail.on('lowered', fn) and call a process.exit() on receiving that event. Ideas?
Many thanks.
I've ended up writing a hook to accomplish what I need. The hook listens for the sails.on('lower') (not 'lowered' as the documentation says!!) and waits a configurable time then calls a process.exit() with a configurable exit code.
If anyone else needs it, create the follwoing api/hooks/exitOnLower.js file...
module.exports = function (sails) {
return {
defaults: {
__configKey__: {
name : 'exitOnlower',
wait : 10000,
active: true,
// exitCode : 2
}
},
initialize: function (cb) {
var active = sails.config[this.configKey].active;
var timeout = sails.config[this.configKey].wait;
var exitCode = sails.config[this.configKey].exitCode;
if (!active) {
return cb();
}
sails.on('lower', function () {
sails.log.verbose("[hook:killOnLower] Sails lower detected, exiting in %sms...", timeout);
setTimeout(function () {
sails.log.warn("[hook:killOnLower] exiting app");
process.exit(exitCode ? exitCode : null);
}, timeout)
});
return cb();
}
};
};
Sails doesn't call process.exit when it lowers because the Sails app might have been started programmatically (via sails.lift() or sails.lower()), and exiting the process in this way would quit the script that called Sails as well.
The fact is that Node scripts are supposed to exit automatically when there's nothing left in the event loop. You can verify this yourself by creating a new Sails app with sails new, and creating a test script in that directory like:
/* testscript.js */
var Sails = require('sails');
Sails.load({hooks: {grunt: false, views: false}}, function(err) {
console.log('lifted sails!');
Sails.lower(function(err) {
console.log('lowered sails!');
});
});
Do node testscript.js on the command line and you'll see the two logs, and then the command prompt again.
All this is to demonstrate that if your app is not lowering, it's because something is keeping it from doing so. The most likely thing would be the database adapter. Some adapters (like Postgres) keep TCP connections alive for awhile. If you wait 30 seconds or so you'll likely see the process exit automatically. If 30 seconds is too long to wait, and if you're not calling Sails programmatically, you can certainly call process.exit yourself. You can wait for the lower event, and then give Sails a bit of time to clean up first:
sails.on('lower', function() {
// Give Sails five seconds to shut down before pulling the plug.
setTimeout(
function() { process.exit(1); },
5000
);
});
Put that in your config/bootstrap.js and you should be good to go.
If you want to find out what's actually hanging your process and preventing it from exiting right now, try the excellent why-is-node-running module.
Note: at the time of this posting, the lower event is incorrectly documented on Sailsjs.com as lowered. This will be fixed ASAP.

Use unregister_chrdev_region in case registration failed

I am learning how to write kernel drivers, and I have a doubt about the proper
usage of the function unregister_chrdev_region.
Right now I have a simple test module with just the init and
exit functions:
static dev_t devn;
int __init my_dev_init(void)
{
devn = MKDEV(0,0);
if(alloc_chrdev_region(&devn,0,1,"my_dev") != 0)
{
return -EBUSY;
}
else
{
return 0;
}
}
void __exit my_dev_exit(void)
{
unregister_chrdev_region(devn,1);
}
My question: is it safe to call unregister_chrdev_region if the registration failed ? I would assume no, but pretty much all example code that I have seen calls unregister_chrdev_region no matter what happened during the initialization.
Registration rarely fails. If registration fails, init function fails, thus insmod command will not succeed in loading the kernel module i.e. test.ko and device node will not be created. So there is no question of unregistration (rmmod). If registration is successful then only we can unregister the driver i.e. unloading the kernel, removal of device node etc... using rmmod. If in init function registration is successful and some other API fails then need to add goto statements, jump to appropriate goto label to unregister and return the appropriate error value. Hope I have cleared your doubt :-)

Run Task Immediately Microsoft.Win32.TaskScheduler

I'm using Task Scheduler Managed Wrapper from Codeplex and I need to fire task as soon as possible and only once. I don't found any API that could execute created task immediately (I can be wrong). So how can I create a trigger that fires only once and as soon as possible?
Found solution here.
using (TaskService ts = new TaskService())
{
string task = "TaskName";
// This will find it even if its down in a folder. Alternately you could call:
// Task t = ts.GetTask(task);
Task t = ts.FindTask(task);
if (t != null)
t.Run();
}

Cancelling an Entity Framework Query

I'm in the process of writing a query manager for a WinForms application that, among other things, needs to be able to deliver real-time search results to the user as they're entering a query (think Google's live results, though obviously in a thick client environment rather than the web). Since the results need to start arriving as the user types, the search will get more and more specific, so I'd like to be able to cancel a query if it's still executing while the user has entered more specific information (since the results would simply be discarded, anyway).
If this were ordinary ADO.NET, I could obviously just use the DbCommand.Cancel function and be done with it, but we're using EF4 for our data access and there doesn't appear to be an obvious way to cancel a query. Additionally, opening System.Data.Entity in Reflector and looking at EntityCommand.Cancel shows a discouragingly empty method body, despite the docs claiming that calling this would pass it on to the provider command's corresponding Cancel function.
I have considered simply letting the existing query run and spinning up a new context to execute the new search (and just disposing of the existing query once it finishes), but I don't like the idea of a single client having a multitude of open database connections running parallel queries when I'm only interested in the results of the most recent one.
All of this is leading me to believe that there's simply no way to cancel an EF query once it's been dispatched to the database, but I'm hoping that someone here might be able to point out something I've overlooked.
TL/DR Version: Is it possible to cancel an EF4 query that's currently executing?
Looks like you have found some bug in EF but when you report it to MS it will be considered as bug in documentation. Anyway I don't like the idea of interacting directly with EntityCommand. Here is my example how to kill current query:
var thread = new Thread((param) =>
{
var currentString = param as string;
if (currentString == null)
{
// TODO OMG exception
throw new Exception();
}
AdventureWorks2008R2Entities entities = null;
try // Don't use using because it can cause race condition
{
entities = new AdventureWorks2008R2Entities();
ObjectQuery<Person> query = entities.People
.Include("Password")
.Include("PersonPhone")
.Include("EmailAddress")
.Include("BusinessEntity")
.Include("BusinessEntityContact");
// Improves performance of readonly query where
// objects do not have to be tracked by context
// Edit: But it doesn't work for this query because of includes
// query.MergeOption = MergeOption.NoTracking;
foreach (var record in query
.Where(p => p.LastName.StartsWith(currentString)))
{
// TODO fill some buffer and invoke UI update
}
}
finally
{
if (entities != null)
{
entities.Dispose();
}
}
});
thread.Start("P");
// Just for test
Thread.Sleep(500);
thread.Abort();
It is result of my playing with if after 30 minutes so it is probably not something which should be considered as final solution. I'm posting it to at least get some feedback with possible problems caused by this solution. Main points are:
Context is handled inside the thread
Result is not tracked by context
If you kill the thread query is terminated and context is disposed (connection released)
If you kill the thread before you start a new thread you should use still one connection.
I checked that query is started and terminated in SQL profiler.
Edit:
Btw. another approach to simply stop current query is inside enumeration:
public IEnumerable<T> ExecuteQuery<T>(IQueryable<T> query)
{
foreach (T record in query)
{
// Handle stop condition somehow
if (ShouldStop())
{
// Once you close enumerator, query is terminated
yield break;
}
yield return record;
}
}