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.
Related
I'm trying to set an initial value to the public ReactiveProperty<string> ConnectionStatus.
public ViewModelConstructor()
{
ConnectionStatus = Observable
.Interval(RefreshInterval)
.Select(x => Observable.FromAsync(() => networkDiscovererService.CanDiscoverAsync("192.168.1.1", RequestTimeout)))
.Concat()
.Select(isConnected => isConnected ? $"connected" : $"not connected")
.ToReactiveProperty();
}
Even if I'm trying to instantiate it like this
public ReactiveProperty<string> ConnectionStatus { get; } =
new ReactiveProperty<string>("Checking connectivity...");
It's still empty until the observable returns something.
Any ideas? I'm using this library.
To get initial value on subscribe (like behaviorSubject, or Replay(1)) using ReactiveProperty ctor:
[Test]
public void ShouldReturnAValuOnSubscribe()
{
var testScheduler = new TestScheduler();
var testableObserver = testScheduler.CreateObserver<int>();
var reactiveProperty = new ReactiveProperty<int>(30);
reactiveProperty.Subscribe(testableObserver);
Assert.AreEqual(30, testableObserver.Messages.Single().Value.Value);
}
To get initial value on subscribe (like behaviorSubject, or Replay(1)) using .ToReactiveProperty():
[Test]
public void ShouldReturnAValuOnToReactiveProperty()
{
var testScheduler = new TestScheduler();
var testableObserver = testScheduler.CreateObserver<int>();
var reactiveProperty = Observable.Never<int>().ToReactiveProperty(40);
reactiveProperty.Subscribe(testableObserver);
Assert.AreEqual(40, testableObserver.Messages.Single().Value.Value);
}
NOT to get initial value on subscribe - change ReactivePropertyMode:
[Test]
public void ShouldNotReturnAnInitialValue_WhenModeIsNone_AndOnSubscribe()
{
var testScheduler = new TestScheduler();
var testableObserver = testScheduler.CreateObserver<int>();
var reactiveProperty = new ReactiveProperty<int>(30, ReactivePropertyMode.None);
reactiveProperty.Subscribe(testableObserver);
Assert.IsEmpty(testableObserver.Messages);
}
Basically, what you're looking for is initial value and ReactivePropertyMode.RaiseLatestValueOnSubscribe flag.
In the first case you forgot to provider ToReactiveProperty() with initial value (e.g. ToReactiveProperty(30))
It should've worked for you in the second case - the mode is set to ReactivePropertyMode.RaiseLatestValueOnSubscribe by default (check ShouldReturnAValuOnSubscribe). Try to set the mode explicitly (like in ShouldNotReturnAnInitialValue_WhenModeIsNone_AndOnSubscribe).
I used ReactiveProperty 3.6.0.
btw, It's not a very good idea to test a connection based on timer :)
i tried this method that I created but it prompts me an error:
Realms.RealmInvalidObjectException:This object is detached. Was it deleted from the realm?'
public void deleteFromDatabase(List<CashDenomination> denom_list)
{
using (var transaction = Realm.GetInstance(config).BeginWrite())
{
Realm.GetInstance(config).Remove(denom_list[0]);
transaction.Commit();
}
}
what is the proper coding for deleting records from database in realm in C# type of coding?
You are doing it the right way. The error message you are getting indicates that the object was removed already. Are you sure it still exists in the realm?
UPDATE:
I decided to update this answer because my comment on the other answer was a bit hard to read.
Your original code should work fine. However, if you want deleteFromDatabase to accept lists with CashDenomination instances that either have been removed already or perhaps were never added to the realm, you would need to add a check. Furthermore, note that you should hold on to your Realm instance and use it in the transaction you created. In most cases, you want to keep it around even longer, though there is little overhead to obtaining it via GetInstance.
public void deleteFromDatabase(List<CashDenomination> denom_list)
{
if (!denom_list[0].IsValid) // If this object is not in the realm, do nothing.
return;
var realm = Realm.GetInstance(config);
using (var transaction = realm.BeginWrite())
{
realm.Remove(denom_list[0]);
transaction.Commit();
}
}
Now, if you want to use identifiers, you could look it up like you do, but still just use Remove:
public void deleteFromDatabase(int denom_id)
{
var realm = Realm.GetInstance(config);
var denom = realm.All<CashDenomination>().FirstOrDefault(c => c.denom_id == denom_id);
if (denom == null) // If no entry with this id exists, do nothing.
return;
using (var transaction = realm.BeginWrite())
{
realm.Remove(denom);
transaction.Commit();
}
}
Finally, if your CashDenomination has denom_id marked as PrimaryKey, you could look it up like this:
public void deleteFromDatabase(int denom_id)
{
var realm = Realm.GetInstance(config);
var denom = realm.ObjectForPrimaryKey<CashDenomination>(denom_id);
if (denom == null) // If no entry with this id exists, do nothing.
return;
using (var transaction = realm.BeginWrite())
{
realm.Remove(denom);
transaction.Commit();
}
}
public void deleteFromDatabase(Realm realm, long cashDenominatorId)
{
realm.Write(() =>
{
var cashDenominator = realm.All<Person>().Where(c => c.Id == cashDenominatorId);
Realm.RemoveRange<CashDenomination>(((RealmResults<CashDenomination>)cashDenominator));
});
}
Which you would call as
Realm realm = Realm.GetInstance(config);
var denom_list = ...
// ...
deleteFromDatabase(realm, denom_list[0].id);
I already made it having this code :) thanks to #EpicPandaForce 's answer.
public void deleteFromDatabase(int denom_ID, int form_ID)
{
//Realm realm;
//and
//RealmConfiguration config = new RealmConfiguration(dbPath, true);
//was initialized at the top of my class
realm = Realm.GetInstance(config);
realm.Write(() =>
{
var cashflow_denom = realm.All<CashDenomination>().Where(c => c.denom_id == denom_ID);
var cashflow_form = realm.All<CashForm>().Where(c => c.form_id == form_ID);
realm.RemoveRange(((RealmResults<CashDenomination>)cashflow_denom));
realm.RemoveRange(((RealmResults<CashForm>)cashflow_form));
});
}
it is now deleting my data without exception :)
The old code I've inherited for Twilio retrieves messages using the absolute PageNumber property of the MessageListRequest but according to the documentation this is obsolete and I should be using GetNextPage and GetPrevPage.
The API metadata shows this as obsolete with the message "Use GetNextPage and GetPreviousPage for paging. Page parameter is scheduled for end of life https://www.twilio.com/engineering/2015/04/16/replacing-absolute-paging-with-relative-paging".
Are there any examples of this usage? I couldn't find any in the documentation except in one of the API test methods and I'm not sure how well I can get to processing multiple pages with this example as a guide.
public class Foo : TwilioBase
{
public string Bar { get; set; }
}
public class FooResult : TwilioListBase
{
public List<Foo> Foos { get; set; }
}
[Test]
public void ShouldGetNextPage()
{
IRestRequest savedRequest = null;
FooResult firstPage = new FooResult();
firstPage.NextPageUri = new Uri("/Foos?PageToken=abc123", UriKind.Relative);
mockClient.Setup(trc => trc.Execute<FooResult>(It.IsAny<IRestRequest>()))
.Callback<IRestRequest>((request) => savedRequest = request)
.Returns(new FooResult());
var client = mockClient.Object;
var response = client.GetNextPage<FooResult>(firstPage);
mockClient.Verify(trc => trc.Execute<FooResult>(It.IsAny<IRestRequest>()), Times.Once);
Assert.IsNotNull(savedRequest);
Assert.AreEqual("/Foos?PageToken=abc123", savedRequest.Resource);
Assert.AreEqual(Method.GET, savedRequest.Method);
Assert.IsNotNull(response);
}
The old usage might look something like so:
var twilio = new TwilioRestClient(config.AccountSid, config.AuthToken);
var result = new List<Message>();
MessageResult tempResult;
int page = 0;
do
{
var request = new MessageListRequest();
request = new MessageListRequest { Count = 1000, DateSent = newestDate, DateSentComparison = ComparisonType.GreaterThanOrEqualTo, PageNumber = page++, To = config.FromNumber };
tempResult = twilio.ListMessages(request);
result.AddRange(tempResult.Messages);
} while (tempResult.NextPageUri != null);
Finally, I built the Twilio API 3.4.1.0 from the twilio-csharp GitHub project instead of NuGet since I need to update it to use the MessagingServiceSid which isn't included in the API yet.
Thanks for any pointers. I'll post a solution if I can figure it out on my own.
Actually, I got it to work now!
MessageResult messages = twilio.ListMessages(request);
do
{
if (messages.Messages != null)
{
foreach (var message in messages.Messages)
{
... process results
}
if (messages.NextPageUri != null)
{
messages = twilio.GetNextPage<MessageResult>(messages);
}
}
} while (messages.NextPageUri != null);
Did you try the example from the API Explorer?
https://www.twilio.com/console/dev-tools/api-explorer/sms/sms-mms-list
var twilio = new TwilioRestClient(AccountSid, AuthToken);
// Build the parameters
var options = new MessageListRequest();
var messages = twilio.ListMessages(options);
foreach (var message in messages.Messages)
{
Console.WriteLine(message.Body);
}
The helper library will automatically fetch from the API as you loop over the list until all records matching your criteria are processed.
You can limit the results with MessageListRequest.
Please give that a try and let me know how it goes.
I am trying to get the notifications on a clone after I change the source item. In our system, when the source item changes, the clone automatically changes as well. However we need to auto-reject the Sitecore notification that says, "A field in the original item has been changed" and gives the review/accept/reject options. The problem is that using GetNotifications() on the clone returns 0 elements - meaning Sitecore didn't find any notifications. However I clearly see them when I reload/re-open the clone.
I tried reloading the item using:
item.Reload();
and
Context.ClientPage.SendMessage(this, "item:load(id=" + item.ID + ")");
before running GetNotifications(), but neither made the count of notifications greater than zero.
Here is my full code used (where copyItem is my clone) int k is a test and it returns 0.
using (new SecurityDisabler())
{
if (copyItem.IsClone)
{
var notifies = Database.GetDatabase("master").NotificationProvider.GetNotifications(copyItem);
int k = -1;
if (notifies != null) k = notifies.Count();
foreach (Notification n in notifies)
{
n.Reject(copyItem);
}
}
}
Note: I'm calling the above code underneath the OnItemSaved event.
I found a helpful post that provided something slightly different from the code I was using. It uses a Sitecore job (async/background process) to run the notifications check and also has a slight delay. This seems to be working well for me now. Finally those notifications aren't showing up anymore!
My final code was:
public void OnItemSaved(object sender, EventArgs args)
{
var item = Event.ExtractParameter(args, 0) as Item;
ReReferenceFieldAndRemoveNotifications(item, args);
...
}
private void ReReferenceFieldAndRemoveNotifications(Item srcItem, EventArgs args)
{
if (srcItem != null && !srcItem.Paths.Path.ToLower().Contains(string.Format("{0}/{1}", "content", "canada")))
{
var destItem = Database.GetDatabase("master").GetItem(srcItem.Paths.Path.Replace("United States", "Canada"));
// Update the clone
Rereferencer.RereferenceFields(srcItem, destItem);
// Now reject the notifications on the clone (accepting would push the US values which we don't want)
using (new SecurityDisabler())
{
if (srcItem.HasClones)
{
var jobOptions = new JobOptions("RejectNotifications", string.Empty, Context.GetSiteName(), this, "RejectNotifications", new object[] { srcItem });
var job = new Job(jobOptions);
jobOptions.InitialDelay = new TimeSpan(0, 0, 0, 1, 0);
JobManager.Start(job);
}
}
}
}
public void RejectNotifications(Item args)
{
// Remove and reject any notifications on the clone.
using (new SecurityDisabler())
{
var item = args;
var clones = item.GetClones(true);
foreach (var clone in clones)
{
var notifications = clone.Database.NotificationProvider.GetNotifications(clone);
foreach (var notification in notifications)
{
clone.Database.NotificationProvider.RemoveNotification(notification.ID);
notification.Reject(clone);
}
clone.Editing.BeginEdit();
try
{
clone.Fields["__Workflow"].Value = args.Fields["__Workflow"].Value;
clone.Fields["__Workflow state"].Value = args.Fields["__Workflow state"].Value;
}
finally
{
clone.Editing.EndEdit();
}
}
}
}
Note: The ReReference code is not related to this solution, you do not need that.
Suppose I have a set of URIs that I am monitoring for availability. Each URI is either "up" or "down", and new URIs to monitor may be added to the system at any time:
public enum ConnectionStatus
{
Up,
Down
}
public class WebsiteStatus
{
public string Uri
{
get;
set;
}
public ConnectionStatus Status
{
get;
set;
}
}
public class Program
{
static void Main(string[] args)
{
var statusStream = new Subject<WebsiteStatus>();
Test(statusStream);
Console.WriteLine("Done");
Console.ReadKey();
}
private static void Test(IObservable<WebsiteStatus> statusStream)
{
}
}
Now suppose in Test() I want to reactively ascertain:
whether all URIs are down (as a bool)
which URIs are down (as IEnumerable<string>)
So Test would end up creating an observable like IObservable<Tuple<bool, IEnumerable<string>>> where the bool indicates whether all URIs are down and the IEnumerable<string> contains those URIs that are.
How do I go about this? My initial thinking is that I would need to group by the URI, then combine the latest from each group into a list that I could then perform a Select against. However, this did not work out due to the way CombineLatest works.
EDIT: Thanks to Matthew's answer I looked into rxx and found that it implemented a CombineLatest overload in exactly the fashion I would have expected in rx out of the box, except that I needed to change it so that it publishes even when there is only a single source stream being combined (by default it was waiting for a minimum of two source streams). Also, I can't justify pulling in an extra 2MB of binaries for the sake of one method, so I have copy/pasted it into my project. Doing so, I was able to solve as follows:
private static void Test(IObservable<WebsiteStatus> statusStream)
{
statusStream
.GroupBy(x => x.Uri)
.CombineLatest()
.Select(
x =>
{
var down = x.Where(y => y.Status == ConnectionStatus.Down);
var downCount = down.Count();
var downUris = down.Select(y => y.Uri).ToList();
return new
{
AllDown = x.Count == downCount,
DownUris = downUris
};
})
.Subscribe(x =>
{
Console.WriteLine(" Sources down ({0}): {1}", x.AllDown ? "that's all of them" : "some are still up", x.DownUris.Aggregate("", (y, z) => y += (z + " | ")));
});
}
The neatest way is to use the Rxx extension in this answer. An alternative is below, it just keeps a list of sites that are down/up.
var downStream = statusStream
.Aggregate<WebsiteStatus, IEnumerable<string>>(new string[0], (down, newStatus) =>
{
if (newStatus.IsUp)
return down.Where(uri => uri != newStatus.Uri);
else if (!down.Contains(newStatus.Uri))
return down.Concat(new string[] { newStatus.Uri });
else
return down;
});
var upStream = statusStream
.Aggregate<WebsiteStatus, IEnumerable<string>>(new string[0], (up, newStatus) =>
{
if (!newStatus.IsUp)
return up.Where(uri => uri != newStatus.Uri);
else if (!up.Contains(newStatus.Uri))
return down.Concat(new string[] { newStatus.Uri });
else
return up;
});
var allDown = upStream.Select(up => !up.Any());