So we have an .NET Core API which uses hangfire as a task scheduler.
On startup, our API starts the following functions :
public void CreateTasks()
{
/* DATABASE TASKS */
SyncDatabaseTask();
/* SMS TASKS */
SendSmsTask();
}
public void SendSmsTask()
{
var taskId = BackgroundJob.Schedule(() => _smsService.SendSms(), TimeSpan.FromMinutes(30));
BackgroundJob.ContinueWith(taskId, () => SendSmsTask());
}
This creates the job SendSmsTask in Hangfire on startup and does not start a second job until the first one has been completed.
The issue that we just noticed however is that whenever our API reboots (server update for example) the existing jobs are still running and news jobs are being added.
So we would like to remove all scheduled or running jobs on startup.
I've looked through the documentation (http://docs.hangfire.io/en/latest/) but couldn't really find a solution for this issue.
This should solve your problem, just note that this is untested.
private void RemoveAllHangfireJobs()
{
var hangfireMonitor = JobStorage.Current.GetMonitoringApi();
//RecurringJobs
JobStorage.Current.GetConnection().GetRecurringJobs().ForEach(xx => BackgroundJob.Delete(xx.Id));
//ProcessingJobs
hangfireMonitor.ProcessingJobs(0, int.MaxValue).ForEach(xx => BackgroundJob.Delete(xx.Key));
//ScheduledJobs
hangfireMonitor.ScheduledJobs(0, int.MaxValue).ForEach(xx => BackgroundJob.Delete(xx.Key));
//EnqueuedJobs
hangfireMonitor.Queues().ToList().ForEach(xx => hangfireMonitor.EnqueuedJobs(xx.Name,0, int.MaxValue).ForEach(x => BackgroundJob.Delete(x.Key)));
}
If you still interest Pieter Alberts solution.
Some little changes on that.
If you use old code and you have old job in db, you will get Format Exception.
In //RecurringJobs section you have to change line like this:
JobStorage.Current.GetConnection().GetRecurringJobs().ForEach(xx => RecurringJob.RemoveIfExists(xx.Id));
TL;DR
Old Code:
private void RemoveAllHangfireJobs()
{
var hangfireMonitor = JobStorage.Current.GetMonitoringApi();
//RecurringJobs
JobStorage.Current.GetConnection().GetRecurringJobs().ForEach(xx => BackgroundJob.Delete(xx.Id));
//ProcessingJobs
hangfireMonitor.ProcessingJobs(0, int.MaxValue).ForEach(xx => BackgroundJob.Delete(xx.Key));
//ScheduledJobs
hangfireMonitor.ScheduledJobs(0, int.MaxValue).ForEach(xx => BackgroundJob.Delete(xx.Key));
//EnqueuedJobs
hangfireMonitor.Queues().ToList().ForEach(xx => hangfireMonitor.EnqueuedJobs(xx.Name,0, int.MaxValue).ForEach(x => BackgroundJob.Delete(x.Key)));
}
New Code:
private void RemoveAllHangfireJobs()
{
var hangfireMonitor = JobStorage.Current.GetMonitoringApi();
//RecurringJobs
JobStorage.Current.GetConnection().GetRecurringJobs().ForEach(xx => RecurringJob.RemoveIfExists(xx.Id)); // this line changed!
//ProcessingJobs
hangfireMonitor.ProcessingJobs(0, int.MaxValue).ForEach(xx => BackgroundJob.Delete(xx.Key));
//ScheduledJobs
hangfireMonitor.ScheduledJobs(0, int.MaxValue).ForEach(xx => BackgroundJob.Delete(xx.Key));
//EnqueuedJobs
hangfireMonitor.Queues().ToList().ForEach(xx => hangfireMonitor.EnqueuedJobs(xx.Name,0, int.MaxValue).ForEach(x => BackgroundJob.Delete(x.Key)));
}
PS Edit:
My Hangfire version is 1.7.9
and using Hangfire.PostgreSql
//Start Hangfire Server
var varJobOptions = new BackgroundJobServerOptions();
varJobOptions.ServerName = "job.fiscal.io";
varJobOptions.WorkerCount = Environment.ProcessorCount * 10;
app.UseHangfireServer(varJobOptions);
app.UseHangfireDashboard("/jobs", new DashboardOptions {
Authorization = new[] { new clsHangFireAuthFilter() }
});
//Remove Duplicte HangFire Server
var varMonitoringApi = JobStorage.Current.GetMonitoringApi();
var varServerList = varMonitoringApi.Servers().Where(r => r.Name.Contains("job.fiscal.io"));
foreach( var varServerItem in varServerList) {
JobStorage.Current.GetConnection().RemoveServer(varServerItem.Name);
}
HF 1.7.28
For me deleting Enqueued jobs like suggested did not work.
Instead, I had to use the following:
hangfireMonitor.Queues().ToList().ForEach(x => x.FirstJobs.Where(j => j.Value.InEnqueuedState).ToList().ForEach(x => BackgroundJob.Delete(x.Key)));
Related
I'am trying to test persistence actor, but behavior is wierd.
My tested actor:
public class PredictionManager : ReceivePersistentActor
{
public override string PersistenceId => _persistanceId;
public PredictionManager(string persistenceId)
{
_persistanceId = persistenceId;
Command<AddPredictionRequest>(OnPrediction);
Recover<SnapshotOffer>(x => OnRecover((PredictionManagerState)x.Snapshot), x => x.Snapshot is PredictionManagerState);
}
private void OnPrediction(AddPredictionRequest request)
{
/* some code */
_state.Add(request);
SaveSnapshot(_state);
}
private void OnRecover(PredictionManagerState state)
{
foreach(var request in state.RequestMap)
{
OnPrediction(request.Value);
}
}
}
My state save all messages and deletes them after manager actor recieve some message. When I try to debug my test, Recover function called first and after this called OnPrediction. My question is - how it's possible? If data stores in momory, why it have SnapshotOffer? Also I have tried to generate new percistenceId from Guid.NewGuid() but it doesn't work.
public void AddPrediction_PassToChild_CreateNewManager_PassToChild()
{
var sender = CreateTestProbe(Sys);
var persistanceId = "AddPrediction_PassToChild_CreateNewManager_PassToChild";
var props = Props.Create(() => new PredictionManager(Mock.Of<IEventBus>(), persistanceId));
var predictionManager = ActorOf(props);
var message = new PredictionManager.AddPredictionRequest(Props.Create(() => new ChildTestActor(sender.Ref)),
new StartPrediction<IPredictionParameter>("a", 1, "a", new Param() ));
//Act
predictionManager.Tell(message, sender);
sender.ExpectMsg<string>(x => x == "ok", TimeSpan.FromSeconds(15));
Sys.Stop(predictionManager);
predictionManager = Sys.ActorOf(props);
sender.ExpectMsg<string>(x => x == "ok", TimeSpan.FromSeconds(15));
Sys.Stop(predictionManager);
}
I found out that default storage for snapshots is LocalStorage not MemoryStorage. So it stores snapshots in files, and this is why it has SnapshotOffer after app restart. But I still can't get why Guid.NewGuid() as persistanceId is not working.
im trying to write unit tests for a class that is written using reactivex.io .
my test code is something like this:
[TestMethod]
public void TestMethod1()
{
string userName = "Moeen";
string password = "moeen123";
string instrument = "Bass";
_loggerMock = new Mock<ILogger>();
_loggerMock.Setup(x => x.RequestInput(Messages.EnterUsername)).Returns(Observable.Return(userName));
_loggerMock.Setup(x => x.RequestInput(Messages.EnterPassword)).Returns(Observable.Return(password));
// _loggerMock.Setup(x => x.ShowProgressIndicator("loading")).Returns(ValueFunction);
var options = Enum.GetValues(typeof(Instrument)).Cast<Instrument>().Select(val => val.ToString());
_loggerMock.Setup(x => x.RequestInput($"{Messages.SelectInstrument} [{string.Join("|", options)}]")).Returns(Observable.Return(instrument));
_loggerMock.Setup(x => x.ShowMessage(""));
_backendMock = new UnreliableFakeBackend();
var result = new SignupFlow(_backendMock, _loggerMock.Object).Run();
result.Subscribe(x =>
{
Assert.AreEqual(true,false);
});
I tested it but the Assert code never gets called inside the subscribe function so the function always asserts true.
as I read the docs I have to write a scheduler to make it work but it doesn't explain well enough to make it work.
I try to build an update request using the C# mongodb driver.
I would like to update a field only if he is not null. Here is the following code :
public void Replace(Core.Entity.Project project)
{
var filter = Builders<Entity.Project>.Filter.Eq(x => x.ProjectNumber, project.ProjectNumber);
var update = BuildUpdateRequest(project);
_mongoCollection.UpdateOne(filter, update);
}
private UpdateDefinition<Entity.Project> BuildUpdateRequest(Core.Entity.Project project)
{
var builder = Builders<Entity.Project>.Update;
var update = builder.Set(x => x.LastUpdateDate, DateTime.UtcNow);
if (!string.IsNullOrEmpty(project.UserId))
{
update.Set(x => x.UserId, project.UserId);
}
}
Unfortunately when I run my unit/integration tests, the data is not updated.
Do you have a better way to use this objects ?
Ok it was easy. Fixed it with :
update = update.Set(x => x.UserId, project.UserId);
I'm having this issue that I've been going crazy over for a few hours now. I've got a table stored in Azure that holds tasks a user wants to accomplish. Each task has a status which can be an integer value of either 1, 2 or 3 corresponding to to do, in progress or completed respectively. I'm trying to create three separate gauges which tell the user how many tasks they have in each of those three categories, but everything I've tried throws a MobileServiceInvalidOperation error and I can't seem to figure out why.
--EDIT--
I was getting a similar issue in another part of my program, and the issue turned out to be one of permissions. Once I included the user authentication code that I had used on another page, the queries I was running on that page started to work. Including that code however, did not stop this exception from being thrown on the code below. I now think that the issue has to do with this code running before the app authenticates the user. If this is the case, how would I go about making sure this code runs after the authentication code does?
--END EDIT--
I'll list out some of my attempts below:
private MobileServiceCollection<SbTask, SbTask> taskItems;
private IMobileServiceTable<SbTask> taskTable = App.MobileService.GetTable<SbTask>();
Attempt 1)
private async void GetTodo()
{
// Can't convert IMobileServiceTableQuery<Int> to
// IMobileServiceQuery<AppName.Models.Sbtask>
IMobileServiceTableQuery<SbTask> query = taskTable
.Where(t => t.Status == 1)
.Select(t => t.Status);
}
Attempt 2)
private async void GetTodo()
{
IMobileServiceTableQuery<int> query = taskTable
.Where(t => t.Status == 1)
.Select(t => t.Status);
// MobileServiceInvalidOperationException
// Additional information: Error: Unauthorized
List<int> statusOne = await query.ToListAsync();
Value = statusOne.Count; // Also tried statusOne.Sum();
}
Attempt 3)
private async void GetTodo()
{
var query = taskTable
.Where(t => t.Status == 1)
.Select(t => t.Status)
.IncludeTotalCount();
// MobileServiceInvalidOperationException
// Additional information: Error: Unauthorized
var results = await query.ToEnumerableAsync();
long count = ((ItotalCountProvider)results).TotalCount;
int counts = Int32.Parse(count.ToString());
List<int> stats = await query.ToListAsync();
for (int i = 0; i < counts; i++)
{
Value += stats[i];
}
}
Attempt 4)
private async void GetTodo()
{
var query = taskTable
.Where(t => t.Status == 1)
.Select(t => t.Status)
.IncludeTotalCount();
// MobileServiceInvalidOperationException
// Additional information: Error: Unauthorized
List<int> stats = await query.ToListAsync();
long count = ((ItotalCountProvider)stats).TotalCount;
int counts = Int32.Parse(count.ToString());
for (int i = 0; i < counts; i++)
{
Value += stats[i];
}
}
Attempt 5)
private async void GetTodo()
{
// MobileServiceInvalidOperationException
// Additional information: Error: Unauthorized
taskItems = await taskTable.ToCollectionAsync();
Value = taskItems.Count(t => t.Status == 1);
}
I've tried a couple of other things that probably aren't even worth mentioning, and I've been searching all over for solutions to this problem--all's I've really learned is that this is a difficult problem and I (obviously) haven't really found a solution.
Thanks in advance to anyone who can help.
So it turns out that the issue was related to authentication. Moving the GetTodo() method out of my viewmodel class and into the xaml.cs file did the trick.
[Subject(typeof(OnceADayProcessor))]
public class When_processing_process_twice
{
private static ICanBeProcessedOnceADay ProcessedOnceADay;
private Establish context = () => { OnceADayProcessor.Now = () => new DateTime(2011, 1, 1, 0, 0, 0, 0); };
private Because of = () =>
{
ProcessedOnceADay = MockRepository.GenerateMock<ICanBeProcessedOnceADay>();
ProcessedOnceADay.Process();
ProcessedOnceADay.Process();
};
private It should_execute = () => ProcessedOnceADay.AssertWasCalled(x => x.Expect(p => p.Process()));
private It should_execute_only_once = () => ProcessedOnceADay.AssertWasNotCalled(x => x.Expect(p => p.Process()));
}
edited solution:
[Subject(typeof(OnceADayProcessor))]
public class When_processing_a_process_twice_at_the_same_day
{
static ICanBeProcessedOnceADay canBeProcessedOnceADay;
Establish context = () =>
{
canBeProcessedOnceADay = A.Fake<ICanBeProcessedOnceADay>();
};
Because of = () =>
{
OnceADayProcessor.Process(canBeProcessedOnceADay);
OnceADayProcessor.Process(canBeProcessedOnceADay);
};
It should_execute_only_once = () =>
A.CallTo(() => canBeProcessedOnceADay.Process()).MustHaveHappened(Repeated.Exactly.Once);
}
var mock = MockRepository.GenerateMock<ICanBeProcessedOnceADay>();
mock.Expect(a => a.Process()).Repeat.Times(1);
...
mock.VerifyAllExpectations();
I would replace the calls to stub.Expect() and stub.VerifyAllExpectations() with stub.AssertWasCalled(x => x.Process(), o => o.Repeat.Once()) in the It. If you have more than one expectation against the stub you can then put each assertion in one It and have them fail (or succeed) independently of each other.
The creation of the stub would go into Establish (essentially, creation of any dependencies and the System Under Test is part of the "arrange" phase in unit testing).
Also consider not to use GenerateMock but GenerateStub as mocks will likely lead to brittle tests when you call other methods than the ones specified with Expect. Libraries like FakeItEasy generally provide better and more discoverable APIs, are easier to learn and will make you fall into the "pit of success".
If you want to ensure that a method is called only once, you need a strict mock:
var mock = MockRepository.GenerateStrictMock<IShouldOnlyBeCalledOnce>();
mock.Expect(a => a.Process()).Repeat.Once();
sut.Process(mock)
mock.VerifyAllExpectations();
If you just use GenerateMock, it will perform an "at least" check. This also goes for Repeats.Times(x) too.