Closed Kimserey closed 6 years ago
@Kimserey, did you consider directly storing grain state in a relational database, rather than storing grain state elsewhere and then post-processing events to persist the grains in a relational DB?
The Orleans indexing project is now here. Its goal is to maintain indexes that are exposed as Orleans collections that can be accessed via the Orleans API. While it would certainly be worthwhile to extend it to support queries over multiple classes, we don't plan to work on adding that functionality anytime soon.
@Kimserey I store grain state in SQL using either entity framework, or the repository pattern. I don't use the built-in orleans grain state methods at all.
From there grains kinda-sorta turn into a read-through/write-through cache of what is in SQL. You can query SQL directly, but it is eventually consistent with active grains.
However querying SQL for filtering/indexing should be okay and fit within your business requirements. E.G. I would query SQL for a list of student names attending a class. once I got the names, then I query all the grains for their current state. I would not read the current state out of SQL... Only query the grain key's.
For simple things and relatively small sets of data I create special index grains, which care about this aspect only.
There is interesting library YesSql created by @sebastienros from asp.net team, used by OrchardCore CMS that can be relevant for sql store provider
YesSql is a .NET Core document database interface over relational databases which allows you to define documents and indexes using plain old CLR objects. The main difference with document databases is that it uses any RDBMS to store them, which gives you all the power of SQL databases like transactions, replication, reporting, ... But the main advantage might be that there is no magic involved, it's pure SQL
Storage provider based on this library can create indexes automatically and give interface for querying
Hey guys thanks a lot for the reply,
@philbe, I had been following the repository and read the paper you published, but there doesn't seem to be a stable release scheduled any time soon (I might be wrong). I did think of storing grain state in relational database as @DarkCow mentioned and I believe this is what I am looking for.
@DarkCow, are you using a custom grain storage? Last time I checked, the state of the grains were stored as blob in the table rather than relational/table-column which defeated the purpose of the relational db for me.
@SebastianStehle , would you have a sample to share?
My current problem is that I am using Orleans as a writing mechanism for purchases
. The model can be seen as accounts
with purchases
getting added to.
accounts
do not hold a list of purchases
instead, it emits a message purchaseAdded
and a implicit stream picks it up and store the purchase in a relational database.
I intentionally did not hold a list of purchases
inside the account
as I am afraid that too many account
activations would use up too much memory.
I could probably switch the relational database for a index grain, would that be what you would do?
@kimserey I would design your code this way.
Don't use the built in grain state stuffs.
Use the standard c# repository pattern, or ef core to read/write/update state using standard SQL stuffs...
Write helper functions like queryPurchaseIdsForAccount. This will help you the grain IDs to get grain references
@DarkCow , that's quite interesting, I actually never considered that option.
So in this scenario, you would just drop the grain state and store everything in SQL?
I don't quite understand 3) what do you mean by This will help you [with] the grain IDs to get grain references
? Would you be able to give me an example?
public class AccountGrain : Grain {
private readonly EfContext _context;
private readonly AccountModel _model
public AccountGrain(EfContext context) {
_context = context;
}
public async Task onActivateAsync() {
_model = await _context.Accounts.Single(a => a.AccountId == this.GetPrimaryKeyLong( ));
}
public async Task BusinessLogicThingy() {
// do stuff with entity framework here!
await _context.SaveAsync();
}
}
// For use elsewhere in the code
var accountForPurchase = _context.Account
.Where(a => a.Purchases.Contains(purchaseId))
.Select(a => a.accountId); // Only want to select accountId.
var accountGrain = _clusterClient.GetGrain<IAccountGrain>(accountForPurchase);
await accountGrain.BusinessLogicThingy();
Thanks! @DarkCow, that's really an interesting idea. I'll try that and see if it fits in the context of my application.
I had been following the indexing of actor state and read the paper published on it but there doesn't seem to be much movement on it.
What would be the recommended approach to persist grain state in relational database in order to query across multiple actors?
For the moment, I have implemented it as such: