UniqueConstraints bundle not picked up by EmbeddableDocumentStore with custom plugins directory - ravendb

We are using EmbeddableDocumentStore for non-production deployments and in general it works great. I stumbled upon an issue which took me few hours to solve and it would be good to know if the behaviour I am experiencing is by design.
I init EmbeddableDocumentStore like this:
var store = new EmbeddableDocumentStore()
{
DataDirectory = dataDirectory,
DefaultDatabase = "DbName",
RunInMemory = false,
UseEmbeddedHttpServer = true,
};
store.Configuration.Port = 10001;
store.Configuration.PluginsDirectory = pluginsDirectory; // this is the important line
store.Configuration.CompiledIndexCacheDirectory = compiledIntexCacheDirectory;
store.Configuration.Storage.Voron.AllowOn32Bits = true;
store.RegisterListener(new UniqueConstraintsStoreListener());
store.Initialize();
With this setup UniqueConstraints are not working on the embedded server.
However, when I put plugins directory to it's default location (WorkingDirectory + /Plugins), it magically starts working. Is it expected behaviour?
More info:
I can reproduce it in Console app and in Web app. In web app, the default location is web root + /Plugins.
After a little bit of investigation I found out that there is a difference in how UniqueConstraints' triggers are registered in store.Configuration.Catalog.Catalogs which might have something to do with the unexpected (for me) behaviour.
With custom PluginDirectory, triggers are registered in store.Configuration.Catalog.Catalogs as BuiltinFitleringCatalog:
When bundle is in the default location, triggers are added to BundlesFilteredCatalog in store.Configuration.Catalog.Catalogs with all other default triggers:

What version of RavenDB?
In RavenDB 3.5 registering plugins on the server-side requires a magic string. Adding this to your example above will probably fix it.
store.Configuration.Settings =
{
{ "Raven/ActiveBundles", "Unique Constraints" }
};

Related

Tracking hangfire background jobs with app insights

I have set up app insights in Asp.net core application. All my web api requests are tracked on app insights and if I have any failures I can simply find them in Failures section.
However, I have also Hangfire background jobs running and if they are failing I can't find them on app insights. Also I have alert rule Whenever the total http server errors is greater than or equal to 1 count and I am not sure if hangfire 5xx errors will go under this condition.
So is there any way to track Hangfire jobs failures and get notified about them?
Hangfire handles most exceptions under the hood, so App Insights is not going to pick them up by default. There is also a bunch of configuration you have to do with App Insights as well.
I wrote a JobFilter for Hangfire which allows you to connect with App Insights, this should be enough to get you going:
https://github.com/maitlandmarshall/MIFCore/blob/master/MIFCore.Hangfire/Analytics/AppInsightsEventsFilter.cs
And for the App Insights configuration:
https://github.com/maitlandmarshall/MIFCore/blob/master/MIFCore.Hangfire/Analytics/TelemetryConfigurationFactory.cs
To put everything together from the above links:
var appInsights = this.rootScope.ResolveOptional<AppInsightsConfig>();
var childScope = ServiceScope = this.rootScope.BeginLifetimeScope("HangfireServiceScope");
var activator = new AutofacLifecycleJobActivator(childScope);
var options = new BackgroundJobServerOptions()
{
Activator = activator,
Queues = new[] { JobQueue.Alpha, JobQueue.Beta, JobQueue.Default, JobQueue.Low }
};
this.globalConfig
.UseFilter(new BackgroundJobContext());
if (!string.IsNullOrEmpty(appInsights?.InstrumentationKey))
{
var telemetryClient = new TelemetryClient(TelemetryConfigurationFactory.Create(appInsights));
this.globalConfig.UseFilter(new AppInsightsEventsFilter(telemetryClient));
}
using (var server = new BackgroundJobServer(options))
{
await server.WaitForShutdownAsync(stoppingToken);
}
There was a nice nuget package created Hangfire.Extensions.ApplicationInsights.
So, install the package:
Install-Package Hangfire.Extensions.ApplicationInsights
and add the line to ConfigureService method:
services.AddHangfireApplicationInsights();
If your solution requires some custom details you can adjust the code from github repository.

Azure Web Jobs Redis (RedLock) & Blob Storage Access Issues

We switched to WebJobs with our background tasks that are starting to work when a new item lands on an Azure Queue. Now we have some weird issues that he seems to have problems accessing Redis RedLock and Storage that I can't explain.
Now the biggest issue we have is RedLock. We are using RedLock.Net for distributed locking. Now this works all fine in our production web application and it also worked on the background workers we had but as soon as we switched to WebJobs he basically failed to aquire the lock. To back this up with some code...we are locking like this:
using (var redisLock = await _redLockConnection.RedisLockFactory.CreateAsync(resource, UserLockExpiryTime, UserLockWaitTime, UserLockRetryTime))
{
// make sure we got the lock
if (redisLock.IsAcquired)
{
// execute code...
}
else
{
throw new CouldNotAcquireRedLockException();
}
}
The problem here is, IsAcquired is always false within a Webjob and I have no clue why!?
The second thing that maybe relates to this problem is deleting a blob file in azure storage that fails with a 404 only within a WebJob.
var file = _blobContainer.GetBlockBlobReference("file.txt");
file?.Delete();
This will fail with a 404 Not found exception within the WebJob.
Is there anything I missed setting up the webjob? Could it be an access problem for write operations? Would be glad for any help!
IsAcquired is always false within a Webjob
I do a test with the following code using RedLock.net in an Azure WebJob, I can acquire lock on resource if the lock is available.
public static void ProcessQueueMessage([QueueTrigger("mymes")] string message, TextWriter log)
{
var azureEndPoint = new RedisLockEndPoint
{
EndPoint = new DnsEndPoint("{YOUR_CACHE}.redis.cache.windows.net", 6380),
Password = "YOUR_ACCESS_KEY",
Ssl = true
};
var eps = new[] { azureEndPoint };
var rlf = new RedisLockFactory(eps);
var resource = "https://{storageaccount}.blob.core.windows.net/{containername}/test.txt";
var expiry = TimeSpan.FromSeconds(50);
var wait = TimeSpan.FromSeconds(10);
var retry = TimeSpan.FromSeconds(1);
using (var redisLock = rlf.Create(resource, expiry, wait, retry))
{
Console.WriteLine("Lock acquired: " + redisLock.IsAcquired);
}
log.WriteLine(message);
}
Result of test:
deleting a blob file in azure storage that fails with a 404
As I mentioned in comment, Please check if that Blob is existing via Azure portal or Azure storage explorer, or call Exists method to check existence of the blob before you delete it.

PhoneGap FileTransfer.upload params no longer posting

I just upgraded from Cordova (PhoneGap) 1.5 to 1.9 today and suddenly my FileTransfer params stopped posting. I can tell because I have the server side debugging the $_POST parameters, and they are now blank. Here is the code being run:
var options = new FileUploadOptions();
options.fileKey="file";
options.fileName=imageURI.substr(imageURI.lastIndexOf('/')+1);
options.mimeType="image/jpeg";
options.chunkedMode=false;
var params = new Object();
params.client_token = "This will not make it across, sadly...";
options.params = params;
var ft = new FileTransfer();
rs = ft.upload(imageURI, "http://www.mysite.com/api/uploadimage",
function() { alert('Yay!'); },
function() { alert('Fail happens..'); }, options, true);
Has this happened to anyone else? Maybe there's a new setting that has to be set?
UPDATE:
Just to make sure it wasn't CodeIgniter causing server side issues, I now have the above code posting to echo.php, which simply does "print var_dump($_REQUEST);". Still no results. I was able to cheat and throw the client token on the URL as a $_GET parameter, but it seems a shame to hack the server side because the client side changed.
I had the same issue with the iOS Cordova 1.9. I found and fixed the bug in the framework code, you can download my fork of Cordova and use the newly patched /dist/Cordova-1.9.0.dmg from it: https://github.com/eschultz/incubator-cordova-ios/
At a quick glance the Android Cordova 1.9 code looked fine. I submitted my changes to Apache to include the fix in their next release.
Hope this helps.

RavenDB in embedded mode - Raven Silverlight Studio (Raven.Studio.xap) not working

I have a small console application doing some persistence with Raven which is working fine, but I just can't get the Raven Studio Web-App working.
I think I have read every article/blog post on the web which is around, but I haven't got it working.
The project is referencing the Raven.Client.Embedded, Raven.Client.Lightweight and Raven.Storage.Esent assemblies)
Here is the really simple code starting up my console app:
class Program
{
static void Main(string[] args)
{
EmbeddableDocumentStore store = new EmbeddableDocumentStore { DataDirectory = #"C:\temp\ravendata", UseEmbeddedHttpServer = true };
store.Initialize();
Console.WriteLine("Initialized");
while (true)
{
string line = Console.ReadLine();
if (line == "w")
{
Changeset cs = CreateChangeset();
using (var session = store.OpenSession())
{
session.Store(cs);
session.SaveChanges();
}
Console.WriteLine("Written.");
}
}
The question is: Where to put the Raven.Studio.xap in order to get it running in the browser (http://localhost:8080/Raven/studio.html)?
It's not working in the bin/debug output folder of my console app (which would be the most logical area where it should be), as well as it isn't if I put it in the root of my console application.
Sorry to ask this thing again, but it seems there is some point I am missing on this to get it up and running. ;)
Thanks for your help, R's, Rene
You are right, I've tried it using a new console application project and had the same issues, altough I copied the file Raven.Studio.xap into the \bin\debug AFTER I had seen the error message for the first time.
I found out, that the reason for this has to do with browser-caching. Even though the file would be available now, the embedded http-server returns 304 Not Modified, because it had sent the If-None-Match header into the request. Therefore, the cached "not-found" page in the browser cache will be used.
I fixed it and sent a patch to Ayende. However the solution now is:
1) make sure Raven.Studio.xap is under \bin\debug
2) clear the browsers cache

Self updating .net CF application

I need to make my CF app self-updating through the web service.
I found one article on MSDN from 2003 that explains it quite well. However, I would like to talk practice here. Anyone really done it before or does everyone rely on third party solutions?
I have been specifically asked to do it this way, so if you know of any tips/caveats, any info is appreciated.
Thanks!
This is relatively easy to do. Basically, your application calls a web service to compare its version with the version available on the server. If the server version is newer, your application downloads the new EXE as a byte[] array.
Next, because you can't delete or overwrite a running EXE file, your application renames its original EXE file to something like "MyApplication.old" (the OS allows this, fortunately). Your app then saves the downloaded byte[] array in the same folder as the original EXE file, and with the same original name (e.g. "MyApplication.exe"). You then display a message to the user (e.g. "new version detected, please restart") and close.
When the user restarts the app, it will be the new version they're starting. The new version deletes the old file ("MyApplication.old") and the update is complete.
Having an application update itself without requiring the user to restart is a huge pain in the butt (you have to kick off a separate process to do the updating, which means a separate updater application that cannot itself be auto-updated) and I've never been able to make it work 100% reliably. I've never had a customer complain about the required restart.
I asked this same question a while back:
How to Auto-Update Windows Mobile application
Basically you need two applications.
App1: Launches the actual application, but also checks for a CAB file (installer). If the cab file is there, it executes the CAB file.
App2: Actual application. It will call a web service, passing a version number to the service and retrieve a URL back if a new version exists (). Once downloaded, you can optionally install the cab file and shut down.
One potiencial issue: if you have files that one install puts on the file system, but can't overwrite (database file, log, etc), you will need two separate installs.
To install a cab: look up wceload.exe http://msdn.microsoft.com/en-us/library/bb158700.aspx
private static bool LaunchInstaller(string cabFile)
{
// Info on WceLoad.exe
//http://msdn.microsoft.com/en-us/library/bb158700.aspx
const string installerExe = "\\windows\\wceload.exe";
const string processOptions = "";
try
{
ProcessStartInfo processInfo = new ProcessStartInfo();
processInfo.FileName = installerExe;
processInfo.Arguments = processOptions + " \"" + cabFile + "\"";
var process = Process.Start(processInfo);
if (process != null)
{
process.WaitForExit();
}
return InstallationSuccessCheck(cabFile);
}
catch (Exception e)
{
MessageBox.Show("Sorry, for some reason this installation failed.\n" + e.Message);
Console.WriteLine(e);
throw;
}
}
private static bool InstallationSuccessCheck(string cabFile)
{
if (File.Exists(cabFile))
{
MessageBox.Show("Something in the install went wrong. Please contact support.");
return false;
}
return true;
}
To get the version number: Assembly.GetExecutingAssembly().GetName().Version.ToString()
To download a cab:
public void DownloadUpdatedVersion(string updateUrl)
{
var request = WebRequest.Create(updateUrl);
request.Credentials = CredentialCache.DefaultCredentials;
var response = request.GetResponse();
try
{
var dataStream = response.GetResponseStream();
string fileName = GetFileName();
var fileStream = new FileStream(fileName, FileMode.CreateNew);
ReadWriteStream(dataStream, fileStream);
}
finally
{
response.Close();
}
}
What exactly do you mean by "self-updating"? If you're referring to configuration or data, then webservices should work great. If you're talking about automatically downloading and installing a new version of itself, that's a different story.
Found this downloadable sample from Microsoft- looks like it should help.
If you want to use a third-party component, have a look at AppToDate developed by the guys at MoDaCo.