I have referenced this link to implement springboot multi-tenancy for two data sources - different databases(same schemas though) - https://anakiou.blogspot.in/2015/08/multi-tenant-application-with-spring.html
It works fine till I did not introduce any multi-threading in my application.
When I added a ExecutorService to do inserts in multiple tables for every record in a csv file - I saw the new threads did not contain information of the original tenant identifier that the rest service call was made with.
Instead, it started using the default tenant in the new threads.
How can we solve this? Will really appreciate any pointers.
EDIT 1: ExecutorService code: Trying to set current tenant as below:
List<Future<Output>> futures = new ArrayList<Future<Output>>();
for (int j = 0; j < myList.size(); j++) {
final Output output= myList.get(j);
Future<Output> future = executorService.submit(new Callable<Output>() {
#Override
public Output call() throws Exception {
**TenantContext.setCurrentTenant(<current tenant goes here>);**
Output currentOutput= someService.executeQueries(output);
return currentOutput;
}
});
futures.add(future);
}
The normal approach to propagate the tenant is by using ThreadLocals. In the blog example, it is using the class RequestContextHolder to store the whole request in a ThreadLocal and then resolving the tenant from there.
When you are changing the thread, thread locals are lost in the new thread unless you take care of setting them again.
I'm doing a family day care app, and thought I'd try DDD/CQRS/ES for it, but I'm running into issues with designing the aggregates well. The domain can be described pretty simply:
A child gets enrolled
A child can arrive
A child can leave
The goal is to track the times of the visits, generate invoices, put notes (eg. what was had for lunch, injuries etc.) against the visits. These other actions will be, by far, the most common interaction with the system, as a visit starts once a day, but something interesting happens all the time.
The invariant I'm struggling with is:
A child cannot arrive if they are already here
As far as I can see, I have the following options
1. Single aggregate root Child
Create a single Child aggregate root, with the events ChildEnrolled, ChildArrived and ChildLeft
This seems simple, but since I want each other event to be associated with a visit, it means the visit would be an entity of the Child aggregate, and every time I want to add a note or anything, I have to source all the visits for that child, ever. Seems inefficient and fairly irrelevant - the child itself, and every other visit, simply isn't relevant to what the child is having for lunch.
2. Aggregate Roots for Child and Visit
Child would source just ChildEnrolled, and Visit would source ChildArrived and ChildLeft. In this case, I don't know how to maintain the invariant, besides having the Visit take in a service for just this purpose, which I've seen is discouraged.
Is there another way to enforce the invariant with this design?
3. It's a false invariant
I suppose this is possible, and I should protect against multiple people signing in the same child at the same time, or latency meaning the use hits the 'sign in' button a bunch of times. I don't think this is the answer.
4. I'm missing something obvious
This seems most likely - surely this isn't some special snowflake, how is this normally handled? I can barely find examples with multiple ARs, let alone ones with lists.
Aggregates
You're talking heavily about Visits and what happened during this Visit, so it seems like an important domain-concept of its own.
I think you would also have a DayCareCenter in which all cared Children are enrolled.
So I would go with this aggregate-roots:
DayCareCenter
Child
Visit
BTW: I see another invariant:
"A child cannot be at multiple day-care centers at the same time"
"Hits the 'sign in' button a bunch of times"
If every command has a unique id which is generated for every intentional attempt - not generated by every click (unintentional), you could buffer the last n received command ids and ignore duplicates.
Or maybe your messaging-infrastructure (service-bus) can handle that for you.
Creating a Visit
Since you're using multiple aggregates, you have to query some (reliable, consistent) store to find out if the invariants are satisfied.
(Or if collisions are rarely and "canceling" an invalid Visit manually is reasonable, an eventual-consistent read-model would work too...)
Since a Child can only have one current Visit, the Child stores just a little information (event) about the last started Visit.
Whenever a new Visit should be started, the "source of truth" (write-model) is queried for any preceeding Visit and checked whether the Visit was ended or not.
(Another option would be that a Visit could only be ended through the Child aggregate, storing again an "ending"-event in Child, but this feels not so good to me...but that's just a personal opinion)
The querying (validating) part could be done through a special service or by just passing in a repository to the method and directly querying there - I go with the 2nd option this time.
Here is some C#-ish brain-compiled pseudo-code to express how I think you could handle it:
public class DayCareCenterId
{
public string Value { get; set; }
}
public class DayCareCenter
{
public DayCareCenter(DayCareCenterId id, string name)
{
RaiseEvent(new DayCareCenterCreated(id, name));
}
private void Apply(DayCareCenterCreated #event)
{
//...
}
}
public class VisitId
{
public string Value { get; set; }
}
public class Visit
{
public Visit(VisitId id, ChildId childId, DateTime start)
{
RaiseEvent(new VisitCreated(id, childId, start));
}
private void Apply(VisitCreated #event)
{
//...
}
public void EndVisit()
{
RaiseEvent(new VisitEnded(id));
}
private void Apply(VisitEnded #event)
{
//...
}
}
public class ChildId
{
public string Value { get; set; }
}
public class Child
{
VisitId lastVisitId = null;
public Child(ChildId id, string name)
{
RaiseEvent(new ChildCreated(id, name));
}
private void Apply(ChildCreated #event)
{
//...
}
public Visit VisitsDayCareCenter(DayCareCenterId centerId, IEventStore eventStore)
{
// check if child is stille visiting somewhere
if (lastVisitId != null)
{
// query write-side (is more reliable than eventual consistent read-model)
// ...but if you like pass in the read-model-repository for querying
if (eventStore.OpenEventStream(lastVisitId.Value)
.Events()
.Any(x => x is VisitEnded) == false)
throw new BusinessException("There is already an ongoning visit!");
}
// no pending visit
var visitId = VisitId.Generate();
var visit = new Visit(visitId, this.id, DateTime.UtcNow);
RaiseEvent(ChildVisitedDayCenter(id, centerId, visitId));
return visit;
}
private void Apply(ChildVisitedDayCenter #event)
{
lastVisitId = #event.VisitId;
}
}
public class CommandHandler : Handles<ChildVisitsDayCareCenter>
{
// http://csharptest.net/1279/introducing-the-lurchtable-as-a-c-version-of-linkedhashmap/
private static readonly LurchTable<string, int> lastKnownCommandIds = new LurchTable<string, bool>(LurchTableOrder.Access, 1024);
public CommandHandler(IWriteSideRepository writeSideRepository, IEventStore eventStore)
{
this.writeSideRepository = writeSideRepository;
this.eventStore = eventStore;
}
public void Handle(ChildVisitsDayCareCenter command)
{
#region example command douplicates detection
if (lastKnownCommandIds.ContainsKey(command.CommandId))
return; // already handled
lastKnownCommandIds[command.CommandId] = true;
#endregion
// OK, now actual logic
Child child = writeSideRepository.GetByAggregateId<Child>(command.AggregateId);
// ... validate day-care-center-id ...
// query write-side or read-side for that
// create a visit via the factory-method
var visit = child.VisitsDayCareCenter(command.DayCareCenterId, eventStore);
writeSideRepository.Save(visit);
writeSideRepository.Save(child);
}
}
Remarks:
RaiseEvent(...) calls Apply(...) instantly behind the scene
writeSideRepository.Save(...) actually saves the events
LurchTable is used as a fixed-sized MRU-list of command-ids
Instead of passing the whole event-store, you could make a service for it if you if benefits you
Disclaimer:
I'm no renowned expert. This is just how I would approach it.
Some patterns could be harmed during this answer. ;)
It sounds like the "here" in your invariant "A child cannot arrive if they are already here" might be an idea for an aggregate. Maybe Location or DayCareCenter. From there, it seems trivial to ensure that the Child cannot arrive twice, unless they have previously left.
Of course, then this aggregate would be pretty long-lived. You may then consider an aggregate for a BusinessDay or something similar to limit the raw count of child arrivals and departures.
Just an idea. Not necessarily the way to solve this.
I would try to base the design on reality and study how they solve the problem without software.
My guess is they use a notebook or printed list and start every day with a new sheet, writing today's date and then taking notes for each child regarding arrival, lunch etc. The case with kids staying the night shouldn't be a problem - checking in day 1 and checking out day 2.
The aggregate root should focus on the process (in your case daily/nightly per-child caring) and not the participating data objects (visit, child, parent, etc.).
I'm missing something obvious
This one; though I would quibble with whether or not it is obvious.
"Child" probably should not be thought of as an aggregate in your domain model. It's an entity that exists outside your model. Put another way, your model is not the "book of record" for this entity.
The invariant I'm struggling with is:
A child cannot arrive if they are already here
Right. That's a struggle, because your model doesn't control when children arrive and leave. It's tracking when those things happen in some other domain (the real world). So your model shouldn't be rejecting those events.
Greg Young:
The big mental leap in this kind of system is to realize that
you are not the book of record. In the warehouse example the
*warehouse* is the book of record. The job of the computer
system is to produce exception reports and estimates of what
is in the warehouse
Think about it: the bus arrives. You unload the children, scan their bar codes, and stick them in the play room. At the end of the day, you reverse the process -- scanning their codes as you load them onto the bus. When the scanner tries to check out a child who never checked in, the child doesn't disappear.
Your best fit, since you cannot prevent this "invariant violation", is to detect it.
One way to track this would be an event driven state machine. The key search term to use is "process manager", but in older discussions you will see the term "saga" (mis)used.
Rough sketch: your event handler is listening to these child events. It uses the id of the child (which is still an entity, just not an aggregate), to look up the correct process instance, and notifies it of the event. The process instance compares the event to its own state, generates new events to describe the changes to its own state, and emits them (the process manager instance can be re-hydrated from its own history).
So when the process manager knows that the child is checked in at location X, and receives an event claiming the child is checked in at location Y, it records a QuantumChildDetected event to track the contingency.
A more sophisticated process manager would also be acting on ChildEnrolled events, so that your staff knows to put those children into quarantine instead of into the playroom.
Working back to your original problem: you need to think about whether Visits are aggregates that exist within your domain model, or logs of things that happen in the real world.
Say I have a User that I want to delete, but the User might be referenced by other tables in the database. Is there a way to check for references to this user before trying to delete or is the best option to just delete and catch/handle the exception that SaveChanges() throws?
Obviously I could check each table where the user might be referenced...but I would rather not as it is referenced in a few places and it just seems like a messy way to do things.
I don't now if you have found a solution to this yet but I'm posting since i run into a similar problem myself. I suppose you could use a query to check for references lets say something like..
bool related = db.Article.Where(i => i.CategoryId == id).Any();
But i believe it is better to catch the exception than to check for references.
For scenarios where you want a required relationship but no cascade delete you
can explicitly override the convention and configure cascade delete behavior with the
Fluent API.
The Fluent API method to use is called WillCascadeOnDelete and takes a Boolean as a
parameter. This configuration is applied to a relationship, which means that you first
need to specify the relationship using a Has/With pairing and then call WillCascadeOn
Delete. Something like:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Article>()
.HasRequired(a => a.Category)
.WithMany(i => i.Articles)
.WillCascadeOnDelete(false);
base.OnModelCreating(modelBuilder);
}
Then you usually get a DbUpdateException or a InvalidOperationException depending on how your data is loaded into memory. You can catch them with a simple statement and add a message to the user.
try
{
db.Category.Remove(category);
db.SaveChanges();
return RedirectToAction("Index");
}
catch (DataException)
{
ModelState.AddModelError("", "Your message here");
return View(category);
}
What WillCascadeOnDelete basically does is that it changes the Delete rule in your database from Cascade to No Action which causes the error to be thrown when a violation occurs.
The overall message here is that you have control over the cascade delete setting, but
you will be responsible for avoiding or resolving possible conflicts caused by
not having a cascade delete present. It worked for me, hope it helps you too.
See also:Configuring Relationships with the Fluent API
I have generated ServiceContext for my CRM organization. I'm able to connect to CRM properly. Since I have all my context configuration in app.config file, I wonder is it possible to get IOrganizationService from already instantiated OrganizationServiceContext?
When I need to access the service reference from multiple places, I usually do it in two steps. First of all I try to see if it's possible to pass it down to the called methods (I'm assuming that you have something like the following).
using (IOrganizationService service
= (IOrganizationService) new OrganizationServiceProxy(...))
{
DoSomething();
DoSomething(service);
}
private void DoSomething(IOrganizationService service) { ... }
When it fails (due to technical setup or just plain dumbness), I set up a private property and in the constructor (or at least the first calling method) assign it a value for future access like this.
class MyClass
{
private IOrganization _service;
private IOrganization _Service
{
get
{
if(_service == null)
_service = (IOrganizationService) new OrganizationServiceProxy(...);
return _service;
}
}
...
}
And if you have a lot of code that operates on the server, you might want to move all that stuff to a separate class and have the calls made to it (with the property setup discussed above).
I'm not fully sure if I got your question correctly so be nice if I'm missing your point.
I have read Evans, Nilsson and McCarthy, amongst others, and understand the concepts and reasoning behind a domain driven design; however, I'm finding it difficult to put all of these together in a real-world application. The lack of complete examples has left me scratching my head. I've found a lot of frameworks and simple examples but nothing so far that really demonstrates how to build a real business application following a DDD.
Using the typical order management system as an example, take the case of order cancellation. In my design I can see an OrderCancellationService with a CancelOrder method which accepts the order # and a reason as parameters. It then has to perform the following 'steps':
Verify that the current user has the necessary permission to cancel an Order
Retrieve the Order entity with the specified order # from the OrderRepository
Verify that the Order may be canceled (should the service interrogate the state of the Order to evaluate the rules or should the Order have a CanCancel property that encapsulates the rules?)
Update the state of the Order entity by calling Order.Cancel(reason)
Persist the updated Order to the data store
Contact the CreditCardService to revert any credit card charges that have already been processed
Add an audit entry for the operation
Of course, all of this should happen in a transaction and none of the operations should be allowed to occur independently. What I mean is, I must revert the credit card transaction if I cancel the order, I cannot cancel and not perform this step. This, imo, suggests better encapsulation but I don't want to have a dependency on the CreditCardService in my domain object (Order), so it seems like this is the responsibility of the domain service.
I am looking for someone to show me code examples how this could/should be "assembled". The thought-process behind the code would be helpful in getting me to connect all of the dots for myself. Thx!
Your domain service may look like this. Note that we want to keep as much logic as possible in the entities, keeping the domain service thin. Also note that there is no direct dependency on credit card or auditor implementation (DIP). We only depend on interfaces that are defined in our domain code. The implementation can later be injected in the application layer. Application layer would also be responsible for finding Order by number and, more importantly, for wrapping 'Cancel' call in a transaction (rolling back on exceptions).
class OrderCancellationService {
private readonly ICreditCardGateway _creditCardGateway;
private readonly IAuditor _auditor;
public OrderCancellationService(
ICreditCardGateway creditCardGateway,
IAuditor auditor) {
if (creditCardGateway == null) {
throw new ArgumentNullException("creditCardGateway");
}
if (auditor == null) {
throw new ArgumentNullException("auditor");
}
_creditCardGateway = creditCardGateway;
_auditor = auditor;
}
public void Cancel(Order order) {
if (order == null) {
throw new ArgumentNullException("order");
}
// get current user through Ambient Context:
// http://blogs.msdn.com/b/ploeh/archive/2007/07/23/ambientcontext.aspx
if (!CurrentUser.CanCancelOrders()) {
throw new InvalidOperationException(
"Not enough permissions to cancel order. Use 'CanCancelOrders' to check.");
}
// try to keep as much domain logic in entities as possible
if(!order.CanBeCancelled()) {
throw new ArgumentException(
"Order can not be cancelled. Use 'CanBeCancelled' to check.");
}
order.Cancel();
// this can throw GatewayException that would be caught by the
// 'Cancel' caller and rollback the transaction
_creditCardGateway.RevertChargesFor(order);
_auditor.AuditCancellationFor(order);
}
}
A slightly different take on it:
//UI
public class OrderController
{
private readonly IApplicationService _applicationService;
[HttpPost]
public ActionResult CancelOrder(CancelOrderViewModel viewModel)
{
_applicationService.CancelOrder(new CancelOrderCommand
{
OrderId = viewModel.OrderId,
UserChangedTheirMind = viewModel.UserChangedTheirMind,
UserFoundItemCheaperElsewhere = viewModel.UserFoundItemCheaperElsewhere
});
return RedirectToAction("CancelledSucessfully");
}
}
//App Service
public class ApplicationService : IApplicationService
{
private readonly IOrderRepository _orderRepository;
private readonly IPaymentGateway _paymentGateway;
//provided by DI
public ApplicationService(IOrderRepository orderRepository, IPaymentGateway paymentGateway)
{
_orderRepository = orderRepository;
_paymentGateway = paymentGateway;
}
[RequiredPermission(PermissionNames.CancelOrder)]
public void CancelOrder(CancelOrderCommand command)
{
using (IUnitOfWork unitOfWork = UnitOfWorkFactory.Create())
{
Order order = _orderRepository.GetById(command.OrderId);
if (!order.CanBeCancelled())
throw new InvalidOperationException("The order cannot be cancelled");
if (command.UserChangedTheirMind)
order.Cancel(CancellationReason.UserChangeTheirMind);
if (command.UserFoundItemCheaperElsewhere)
order.Cancel(CancellationReason.UserFoundItemCheaperElsewhere);
_orderRepository.Save(order);
_paymentGateway.RevertCharges(order.PaymentAuthorisationCode, order.Amount);
}
}
}
Notes:
In general I only see the need for a domain service when a command/use case involves the state change of more than one aggregate. For example, if I needed to invoke methods on the Customer aggregate as well as Order, then I'd create the domain service OrderCancellationService that invoked the methods on both aggregates.
The application layer orchestrates between infrastructure (payment gateways) and the domain. Like domain objects, domain services should only be concerned with domain logic, and ignorant of infrastructure such as payment gateways; even if you've abstracted it using your own adapter.
With regards to permissions, I would use aspect oriented programming to extract this away from the logic itself. As you see in my example, I've added an attribute to the CancelOrder method. You can use an intercepter on that method to see if the current user (which I would set on Thread.CurrentPrincipal) has that permission.
With regards to auditing, you simply said 'audit for the operation'. If you just mean auditing in general, (i.e. for all app service calls), again I would use interceptors on the method, logging the user, which method was called, and with what parameters. If however you meant auditing specifically for the cancellation of orders/payments then do something similar to Dmitry's example.