Calling Email OnError from ScriptTask of SSIS - ssis

I have a simple SSIS package with a single script task on it. I have an OnError event with a Send Mail task.
All i'm doing is testing to see if i can send an email when i detect an error withing my script.
However the variable i use to hold the Error message for my email causes an error.
"A deadlock was detected while trying to lock variable "User::errMsg" for read access. "
Here is the very simple script
public void Main()
{
try
{
int x = 2;
if (x ==2)
{
throw new Exception("The number was 2");
}
Dts.TaskResult = (int)ScriptResults.Success;
}
catch(Exception e)
{
Dts.Variables["errMsg"].Value = e.Message;
Dts.Events.FireError(-1, "here", "my error", "", 0);
Dts.TaskResult = (int)ScriptResults.Failure;
}
How can i pass a message to my send email when an error occurs in my script task ?

SSIS variables are locked and are relased only in its Post Execute event .In your case errMsg variable gets locked by the script task and the same time the variable is accessed in On Error event by the SendMail component creating a deadlock situation .You need to specifically unlock the variable before it is accessed by other components during its execution phase.
Try this :-
catch (Exception e)
{
Variables lockedVariables = null;
Dts.VariableDispenser.LockOneForWrite("errMsg", ref lockedVariables);
lockedVariables["errMsg"].Value = e.Message;
lockedVariables.Unlock();
Dts.Events.FireError(-1, "here", "my error", "", 0);
Dts.TaskResult = (int)ScriptResults.Failure;
}
This will ensure that before the error occurs ,the variable is unlocked and can be accessed in execution events such as On Error or OnExecStatusChanged.
More on how to handle these type of deadlocks is explained by Todd McDermid in his blog

Related

SSIS 2019 - Failed to load project files from storage object

I have upgraded SSIS package from SQL Server 2016 to SQL Server 2019. I am getting below error while calling host.CurrentScriptingEngine.LoadProjectFromStorage() as well as host.SaveScriptProject() from script task. It's not able to load it and save it. What needs to be done to make it work?
Code:
private void RecompileScriptSource()
{
IDTSComponentMetaData100 srcComp = m_Pipeline.ComponentMetaDataCollection[BASE_SCRIPT_SOURCE_COMPONENT];
// Get design time instance of script source
CManagedComponentWrapper scriptSourceWrapper = srcComp.Instantiate();
// Get script host & save
try
{
ScriptComponentHost host = (scriptSourceWrapper as IDTSManagedComponent100).InnerObject as ScriptComponentHost;
if (host == null)
{
throw new Exception("Failed to get access to the host object for the script component.");
}
log(host.ProjectTemplatePath+"-----"); //testing or debugging purpose
if (!host.LoadScriptFromComponent()) // This returns false
{
throw new Exception("Failed to load script information from component.");
}
VSTAComponentScriptingEngine engine = host.CurrentScriptingEngine;
if (engine.VstaHelper == null)
{
throw new Exception("Vsta 3.0 is not installed properly");
}
// Facing error here
if (!host.CurrentScriptingEngine.LoadProjectFromStorage())
{
throw new Exception("Failed to load project files from storage object");
}
if (!host.SaveScriptProject())
{
throw new Exception("Failed to save project");
}
else
{
log("Saved script project");
}
engine.DisposeVstaHelper();
}
finally
{
log("Finished saving (or compiling or whatever");
}
}

Nancy Exception in RequestStartup

I'm using Nancy to create a web api. I have a signed token that is passed in from the user to authenticate. This authentication is doen in the RequestStartup method in my own Bootstrapper. Now in some cases, for instance when I can't veryfy the signed token I would like to just be able to throw an exception and have that handled byt the OnError hanhdler in Nancy. However an exception thrown before the RequestStartup is finsihed isn't caught. The request generates a 500 error and I would like to return something else with my own error information.
I have the obvious case where I throw an exception but also possibilities of an exception being thrown in the GetIdentity() method.
I'm looking for any input in how to handle this.
protected override void RequestStartup(TinyIoCContainer container, IPipelines pipelines, NancyContext context)
{
base.RequestStartup(container, pipelines, context);
pipelines.OnError.AddItemToStartOfPipeline((ctx, exception) =>
container.Resolve<IErrorHandler>().HandleException(ctx, exception));
var identity = container.Resolve<IAuthenticationController>().GetIdentity();
var configuration = new StatelessAuthenticationConfiguration(_ => identity);
StatelessAuthentication.Enable(pipelines, configuration);
var logManager = new LogManager(context);
pipelines.AfterRequest.AddItemToEndOfPipeline(_ => logManager.Log());
try
{
X509Certificate2 clientCert = context.Request.ClientCertificate as X509Certificate2;
container.Resolve<ICertificateValidator>().Validate(clientCert);
}
catch (Exception ex)
{
throw new MklServerAuthenticationException(ErrorCodes.WrongOrNonexistingCertificate, ex);
}
}
Figured out a way to solve the above problem and thought somebody else might like to know. Replace the line in my code above, containing the GetIdentity() call, with the following:
Identity identity = null;
try
{
identity = container.Resolve<IAuthenticationController>().GetIdentity(requestInfo);
}
catch (Exception ex)
{
var exception = new MklAuthentcationException(ErrorCodes.TokenInvalid, ex);
context.Response = container.Resolve<IErrorHandler>().HandleException(context, exception);
pipelines.BeforeRequest.Invoke(context, CancellationToken.None);
}
I'm using the fact stated in nancy that:
The PreRequest hook is called prior to processing a request. If a hook returns a non-null response then processing is aborted and the response provided is returned.
So by setting a response (my error in this case) on the PreRequest hook and invoking it my error is returned and execution is stopped.
Maybe not the nicest solution... If you can figure out something better please let me know.

Maintain retry state during async that throws exception

So I have a UI thread. Person clicks something because they feel like it. So click triggers some function calls. One of the underlying function calls uses CDROM driver that reads dirty discs by trying a couple of times and making that crazy thumping.
So I want a responsive UI and i put await on my function call. So when person clicks, function relinquishes control to UI thread. Function tries to read the CDROM, but it is really dirty so it throws an exception to its caller. That caller counts the number of retries and keeps trying three times.
So, if this is all await, where do I keep the count?
If I keep the count in a lower level and that level relinquishes with await, it can't keep retrying until three attempts because IT IS RELINQUISHED.
But if I don't relinquish, I can't maintain a responsive UI.
Do I keep the count in the Task object? And exactly which thread/await level can be responsible for checking the retry count?
You can put your retry logic wherever is most appropriate. await works perfectly well with try:
public async Task PerformOperationAsync(int retries)
{
while (retries != 0)
{
try
{
await PerformSingleOperationAsync();
return;
}
catch (Exception ex)
{
Log(ex);
--retries;
}
}
}
The code above will ignore failures if it runs out of retries. You can also throw the last error:
public async Task PerformOperationAsync(int retries)
{
while (true)
{
try
{
await PerformSingleOperationAsync();
return;
}
catch (Exception ex)
{
Log(ex);
if (--retries == 0)
throw;
}
}
}
Throwing the first error or a collection of all the errors is left as an exercise for the reader. ;)

subscribeToPullNotifications doesn't detect new emails in inbox

i am trying to detect new emails in inbox using subscribeToPullNotifications as follows:
PullSubscription subscription = service.subscribeToPullNotifications(
folder, 1, null, EventType.NewMail);
GetEventsResults events = subscription.getEvents();
System.out.println("####### EVENTS: "
+ events.getItemEvents().toString());
for (ItemEvent itemEvent : events.getItemEvents()) {
if (itemEvent.getEventType() == EventType.NewMail) {
EmailMessage message = EmailMessage.bind(service,
itemEvent.getItemId());
System.out.println("######## NEW EMAIL MESSAGE IS: "
+ message.getSubject());
}
}
but the events.getItemEvents() is always empty, even i can see new emails in the inbox.
also how to make the above code is always repeated while the application is running, so that each minute it check for new emails.
Here it depends on when you are calling this, if suppose you are calling this as particular interval then you need to pass "WaterMark" of previous response in new request, else all events which occurred in between would be lost.
method : subscription.getWaterMark()
need to pass this as thrid argument to method subscribeToPullNotifications()
else you can continously pull on the same service by placing that in loop :
while (true) {
GetEventsResults events = null;
try {
events = subscription.getEvents();
} catch (Exception e1) {
e1.printStackTrace();
}
for (ItemEvent itemEvent : events.getItemEvents()) {
// do something...
}
}
But this would continuously pull from server increasing load, so rather use first approach by subscribing at regular interval, and passing previous water-mark in request.

How to pass errors conditions

In web app development I would like a consistent way to catch and report error conditions. For example, a database update routine may detect a variety of error conditions and ideally I would like the application to capture them and report gracefully. The code below din't work because retdiag is undefined when error is thrown...
function saveData(app,e) {
var db ;
var retdiag = "";
var lock = LockService.getPublicLock();
lock.waitLock(30000);
try {
// e.parameters has all the data fields from form
// re obtain the data to be updated
db = databaseLib.getDb();
var result = db.query({table: 'serviceUser',"idx":e.parameter.id});
if (result.getSize() !== 1) {
throw ("DB error - service user " + e.parameter.id);
}
//should be one & only one
retdiag = 'Save Data Finished Ok';
}
catch (ex) {
retdiag= ex.message // undefined!
}
finally {
lock.releaseLock();
return retdiag;
}
}
Is there a good or best practice for this is GAS?
To have a full error object, with message and stacktrace you have to build one, and not just throw a string. e.g. throw new Error("DB error ...");
Now, a more "consistent" way I usually implement is to wrap all my client-side calls into a function that will treat any errors for me. e.g.
function wrapper_(f,args) {
try {
return f.apply(this,args);
} catch(err) {
;//log error here or send an email to yourself, etc
throw err.message || err; //re-throw the message, so the client-side knows an error happend
}
}
//real client side called functions get wrapped like this (just examples)
function fileSelected(file,type) { return wrapper_(fileSelected_,[file,type]); }
function loadSettings(id) { return wrapper_(loadSettings_,[id]); }
function fileSelected_(file,type) {
; //do your thing
}
function loadSettings_(id) {
; //just examples
throw new Error("DB error ...");
}