Giter Site home page Giter Site logo

edwinvw / pitstop Goto Github PK

View Code? Open in Web Editor NEW
1.1K 99.0 455.0 10.86 MB

This repo contains a sample application based on a Garage Management System for Pitstop - a fictitious garage. The primary goal of this sample is to demonstrate several software-architecture concepts like: Microservices, CQRS, Event Sourcing, Domain Driven Design (DDD), Eventual Consistency.

License: Apache License 2.0

C# 18.11% PowerShell 0.58% HTML 21.07% JavaScript 29.08% CSS 14.27% Ruby 0.01% Shell 0.66% Dockerfile 0.35% SCSS 15.88%
microservices-architecture cqrs event-driven event-sourcing ddd sample-app message-broker netcore docker docker-compose

pitstop's Introduction

Pitstop - Garage Management System

This repo contains a sample application based on a Garage Management System for Pitstop - a fictitious garage / car repair shop. The primary goal of this sample is to demonstrate several software-architecture concepts like:

  • Microservices
  • CQRS
  • Event driven Architecture
  • Event sourcing
  • Domain Driven Design (DDD)
  • Eventual Consistency

and how to use container-technologies like:

  • Docker
  • Kubernetes
  • Istio (service-mesh)
  • Linkerd (service-mesh)

See the Wiki for this repository for more information about the solution and instructions on how to build, run and test the application using Docker-compose and Kubernetes.

This is an actual garage somewhere in Dresden Germany. Thanks to Thomas Moerkerken for the picture!

pitstop's People

Contributors

amolenk avatar broodjetom avatar dependabot[bot] avatar edwinvw avatar jeroenhe avatar jmezach avatar mthmulders avatar mve avatar nikolaybadin avatar nileshgule avatar olafski avatar ptoonen avatar rolfhuisman avatar ronaldbosma avatar vrooijen avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

pitstop's Issues

Wiki mentions running Kubernetes dashboard, but it seems to have moved

Hi @EdwinVW,

Finally got around to checking your pitstop app, after your talk on service mesh/istio

On this page on your wiki you mention using Kubernetes dashboard. But the command given causes an error:
unable to read URL

It seems the .yaml and everything seems to have moved within githubusercontent.com from:

https://raw.githubusercontent.com/kubernetes/dashboard/master/aio/deploy/recommended/kubernetes-dashboard.yaml\

to below url as given in the command in the README.md of https://github.com/kubernetes/dashboard:

kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.2.0/aio/deploy/recommended.yaml

RabbitMQ Connection approach

Hi @EdwinVW

I have a question around Rabbit MQ Connection approach

In this project we are maintaining Host, UserName and Password separately and it is working totally fine as I am able to connect Rabbitmq running in docker or Rabbitmq running locally without docker

RabbitMQ Connection approaches

Approach 1

var factory = new ConnectionFactory { HostName = _host, UserName = _username, Password = _password}
using (var connection = factory.CreateConnection())

Approach 2

var factory = new ConnectionFactory {Uri = new Uri(_uri)};
using (var connection = factory.CreateConnection())

I see approach 2 is bit more common on internet where they maintain complete uri(similar to connection string) like below
"Uri": "amqp://rabbitmquser:DEBmbwkSrzy9D1T9cJfa@rabbitmq"

Sir can you please outline the pros and cons for both approaches

'fanout' with parallel service management?

Hi Edwin, thank you very much for answering my last question about why using 'fanout' with RabbitMQ in this tutorial! I am very curious about implementing the parallel services using 'fanout' in RabbitMQ, as the tutorial in RabbitMQ tells that you could have several 'Consumer' services with one 'Publisher' so that message in queue can be distributed into parallel services to improve the performance. So in your project for example, does it work like you could have

  • one(1) UserManagement Service running
  • two(2) VehicleManagement Services running - so these vehicle services could handle the 'register' parallel with receiving message publishing from 'UserManagement'
  • three(3) WorkshopManagement Services running - so these workshop services could handle the 'planning' work parallel.
    Do you think the above scenario could be achieved in your project? If so, how should we create same services in multiply ports? Can we or should we do it through 'Docker'? Because as of now I only know 'Docker' may create same service with one single port at a time.

Solution needs security

Add security based on OAUTH2/OpenIDConnect to the solution. Let's use IdentityServer to implement this.

Questions regarding - Upgrade to .NET Core 3.0

Hi @EdwinVW

I have a question around one of your old commit i.e. related to Upgrade to .NET Core 3.0 c8db950

Here I am not sure, why have you removed AutoMapper reference and instead you have added your own Mappers class under Pitstop.WorkshopManagementAPI.Mappers namespace.


Actually I was using the older version of Pitstop that was on .net core 2.2 and I was trying to migrate that locally on my machine to .net core 3.1

I am able to migrate all the projects successfully however something weird was happening with WorkshopManagementAPI.WorkshopPlanningController where PlanMaintenanceJobAsync action was not being called in migrated project(core 3.1). and probably PlanMaintenanceJob command was causing some kind of issue.

So I have gone through all your changes and I replicated your approach where I have also removed AutoMapper and make use of your new class, which has solved my problem.

However I am still not very much sure what was the actual root cause and how is it fixing this problem.
Kindly help sir.

Context map workshop management precision

Hi,

many thanks for your work, I really appreciate the fact that you detailed all the steps of your design, especially concerning the Event storming. It now makes sense to me on how to design a DDD architecture from this kind of analysis.

I need some help on the context map part (https://raw.githubusercontent.com/wiki/EdwinVW/pitstop/img/contextmap.png):

  1. How about legend : what does the underlined and the italic entity means ? Do you used Miro as well to produce it ?

  2. If we speak about the workshop management bounded context, the workshop planning appears to be the aggregate root, the maintenance job is a kind of dependance, but in code the class MaintenanceJob is not "tagged" entity, valueobject, nor aggregate.
    But if we link the bounded context on the context map to the eventstorming schema (https://raw.githubusercontent.com/wiki/EdwinVW/pitstop/img/event-storming-result.png) we see that workshop planning and maintenance job appears as Aggregate which lead me to think that MaintenanceJob is an Aggregate, could you confirm ?

  3. What about Read Model : I don't understand why in Customer bounded context there is no ReadModel but in Vehicle there is the customer Read Model, could you explain what it represents please ?

Many thanks

Big Thank you - along with few quick questions around "WorkshopManagementAPI"

Thanks a lot @EdwinVW for helping community by sharing such an awesome work, great help for us.
This is one of the best code repository I have found so far on

I have following quick questions kindly help.

  1. Why did you sagrigated "WorkshopManagementAPI" and "WorkshopManagementEventHandler" project.
    I think "WorkshopManagementEventHandler" can be merged under "WorkshopManagementAPI" project
    since "WorkshopManagementAPI" is most important part and that should be always up and running so its event handler should be there as well.
    kindly let us know your thoughts/vision

  2. Since you are saving customer data in all databases then why didn't you save that(customer data) in "VehicleManagement" database. any special case?

  3. Q 3) What is purpose of defining special RefDataController and what does refdata means here?

  4. What does "fanout" means
    model.ExchangeDeclare(_exchange, "fanout", durable: true, autoDelete: false);

Waiting for your response.

Debugging Microservices via VS2017

Hi, @EdwinVW . Thank you for great demo example of Microservices arhitecture. =)
I've imported all the projects to new solution file in VS2017. Now I would like to debug them via VS2017 so I've added Container-Orchestrator Support for each project (Docker-Compose), but I've realize that original dockerfile(s) and docker-compose.yml is not working anymore out of the box. Is there any chance to provide us modified dockerfiles and docker-compose.yml to be able to debug all services via VS2017. Or maybe is there any other more elegant solution to debug microservices via VS2017?
Thank you for your time and reply.

All the APIs showing Offline while working on docker containers

I have been working on this project for a while and started to deploy on docker containers, but having some issue while doing so, I hope you can give me some ideas about the problem. Docker compose build fine but does not render the pages as it should be. Following are my docker files setup :-

Formerly i have tried to apply docker file to all the projects but after having this problem I tried to start from a project rather than whole therefore, I have tried to recreate/reproduce the problem with a customer management project:-

Docker file CustomerManagement API

FROM mcr.microsoft.com/dotnet/core/aspnet:2.2 AS base
WORKDIR /app
EXPOSE 80

FROM mcr.microsoft.com/dotnet/core/sdk:2.2 AS build
WORKDIR /src
COPY ["src/CustomerManagement/CustomerAPI/CustomerAPI.csproj", "src/CustomerManagement/CustomerAPI/"]

COPY . .
WORKDIR "/src/src/CustomerManagement/CustomerAPI"
RUN dotnet build "CustomerAPI.csproj" -c Release -o /app
RUN dotnet restore -s https://api.nuget.org/v3/index.json -s https://www.myget.org/F/autoweb/api/v3/index.json


FROM build AS publish
RUN dotnet publish "CustomerAPI.csproj" -c Release -o /app

HEALTHCHECK --interval= --timeout= --retries=1 CMD curl --silient --fail http://localhost:5000/hc || exit 1

FROM base AS final
WORKDIR /app
COPY --from=publish /app .
ENTRYPOINT ["dotnet", "CustomerAPI.dll"]

Launch settings.json

{
  "iisSettings": {
    "windowsAuthentication": false,
    "anonymousAuthentication": true,
    "iisExpress": {
      "applicationUrl": "http://localhost:5000",
      "sslPort": 0
    }
  },
  "profiles": {
    "IIS Express": {
      "commandName": "IISExpress",
      "launchBrowser": true,
      "launchUrl": "index.html",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    },
    "CustomerAPI": {
      "commandName": "Project",
      "launchBrowser": true,
      "launchUrl": "index.html",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      },
      "applicationUrl": "http://localhost:5000"
    }
  }
}

Docker file Web:-

FROM mcr.microsoft.com/dotnet/core/aspnet:2.2 AS base
WORKDIR /app
EXPOSE 80

FROM mcr.microsoft.com/dotnet/core/sdk:2.2 AS build
WORKDIR /src
COPY ["src/WebManagement/Web/Web.csproj", "src/WebManagement/Web/"]

COPY . .
WORKDIR "/src/src/WebManagement/Web"
RUN dotnet build "Web.csproj" -c Release -o /app
RUN dotnet restore -s https://api.nuget.org/v3/index.json -s https://www.myget.org/F/autoweb/api/v3/index.json


FROM build AS publish
RUN dotnet publish "Web.csproj" -c Release -o /app

HEALTHCHECK --interval=30s --timeout=3s --retries=1 CMD curl --silent --fail http://localhost:7000/hc || exit 1


FROM base AS final
WORKDIR /app
COPY --from=publish /app .
ENTRYPOINT ["dotnet", "Web.dll"]

Launch settings.json

{
  "iisSettings": {
    "windowsAuthentication": false,
    "anonymousAuthentication": true,
    "iisExpress": {
      "applicationUrl": "http://localhost:7000",
      "sslPort": 0
    }
  },
  "profiles": {
    "IIS Express": {
      "commandName": "IISExpress",
      "launchBrowser": true,
      "launchUrl": "http://localhost:7000",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    },
    "Web": {
      "commandName": "Project",
      "launchBrowser": true,
      "launchUrl": "http://localhost:7000",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      },
      "applicationUrl": "http://localhost:7000"
    }
  }
}

Docker compose.yml file

version: '3.4'

services:

  logserver:
    image: datalust/seq:latest

  sqlserver:
    image: mcr.microsoft.com/mssql/server:2017-latest

  rabbitmq:
    image: rabbitmq:3-management-alpine

  customerapi:
    image: ${DOCKER_REGISTRY-}customerapi
    build:
      context: .
      dockerfile: src/CustomerManagement/CustomerAPI/Dockerfile
    depends_on:
      - sqlserver
      - rabbitmq

  web:
    image: ${DOCKER_REGISTRY-}web
    build:
      context: .
      dockerfile: src/WebManagement/Web/Dockerfile
    depends_on:
      - customerapi

docker-compose.override.yml file

version: '3.4'

services:
  logserver:
    container_name: logserver
    ports:
      - "5341:80"
    environment:
      - ACCEPT_EULA
      
  sqlserver:
    container_name: sqlserver
    ports:
      - "5433:1433"
    volumes:
      - sqlserverdata:/var/opt/mssql
    environment:
      - ACCEPT_EULA=Y
      - MSSQL_PID=Developer
      - SA_PASSWORD=Pass@word

  rabbitmq:
    container_name: rabbitmq
    ports:
      - "15672:15672"
      - "5672:5672"
    volumes:
      - rabbitmqdata:/var/lib/rabbitmq    
    environment:
      - RABBITMQ_DEFAULT_USER=rabbitmquser
      - RABBITMQ_DEFAULT_PASS=Pass@word

  customerapi:
    environment:
      - ASPNETCORE_ENVIRONMENT=Production
      - ASPNETCORE_URLS=http://0.0.0.0:80
    ports:
      - "5000:80"

  web:
    environment:
      - ASPNETCORE_ENVIRONMENT=Production
      - ASPNETCORE_URLS=http://0.0.0.0:80
    ports:
      - "7000:80"

volumes:
  sqlserverdata:
    external: true
  rabbitmqdata:
    external: true

When Refit (RestClient) try to fetch a record from the customerapi (GetCustomers) endpoint, where problem started to happen. I don't know how to step into other projects while debugging from docker compose. I have set a break point in couple of places but it won't hit the customerapi controller action method, since it is a micro-service being called by web front end. I have extracted following errors from a long lines of stack traces if you can help:-

[16:02:33 INF] Start processing HTTP request GET http://localhost:5000/api/customers
[16:02:33 INF] Sending HTTP request GET http://localhost:5000/api/customers
"GET CustomerManagement/Index","ai.location.ip":"172.20.0.1","ai.internal.sdkVersion":"rdddsc:2.10.0-32157","ai.internal.nodeName":"ec1567d9102f.(none)"},"data":{"baseType":"RemoteDependencyData","baseData":{"ver":2,"name":"GET /api/customers","id":"|1a08fcc1445823449b91fe1f785d0f1e.da75cb80_1.","data":"http://localhost:5000/api/customers","duration":"00:00:01.5894365","resultCode":"Faulted","success":false,"type":"Http","target":"localhost:5000","properties":{"DeveloperMode":"true","Error":"Cannot assign requested address","AspNetCoreEnvironment":"Production","_MS.ProcessedByMetricExtractors":"(Name:'Dependencies', Ver:'1.1')"}}}}

[11:16:04 INF] Start processing HTTP request GET http://localhost:5000/api/customers
web_1          | [11:16:04 INF] Sending HTTP request GET http://localhost:5000/api/customers
web_1          | [11:16:04 WRN] Error occured during request-execution. Polly will retry. Exception: Cannot assign requested address
web_1          | [11:16:04 INF] Start processing HTTP request GET http://localhost:5000/api/customers
web_1          | [11:16:04 INF] Sending HTTP request GET http://localhost:5000/api/customers
web_1          | [11:16:04 WRN] Error occured during request-execution. Polly will retry. Exception: Cannot assign requested address
web_1          | [11:16:04 INF] Start processing HTTP request GET http://localhost:5000/api/customers
web_1          | [11:16:04 INF] Sending HTTP request GET http://localhost:5000/api/customers
web_1          | [11:16:04 WRN] Error occured during request-execution. Polly will retry. Exception: Cannot assign requested address
web_1          | [11:16:04 INF] Start processing HTTP request GET http://localhost:5000/api/customers
web_1          | [11:16:04 INF] Sending HTTP request GET http://localhost:5000/api/customers
web_1          | [11:16:04 WRN] Error occured during request-execution. Polly will retry. Exception: Cannot assign requested address
web_1          | [11:16:04 INF] Start processing HTTP request GET http://localhost:5000/api/customers
web_1          | [11:16:04 INF] Sending HTTP request GET http://localhost:5000/api/customers
web_1          | [11:16:04 WRN] Error occured during request-execution. Polly will retry. Exception: Cannot assign requested address


I have tried to run your project but it also give me problem same at WorkshopmanagementAPI but it does display customer and vehicle api. I don't understand where is the problem. I have spent quite a bit time to do a research on it, but could not find any answer therefore i have posted for your help. Hope you won't mind it.

Thanks

Service communication and database

Hi,
I am a bit confused, I can't see any service communication for shared data.
It looks like it is copying data to the services database, wouldn't this cause issues with keeping data up to date?

E.g. many services have a table for "Customer" meaning that them databases have information copied from another database.

Wouldn't it be better to generate a messaging event to a "customer service" and then store the ID in the service that is using that customers information?

Please let me know if I have got anything wrong here.

RabbitMQ localhost not working after running docker-compose

RabbitMQ localhost not working after running docker-compose up command

Getting following error on login
ReferenceError: disable_stats is not defined ReferenceError: disable_stats is not defined at Object.process (eval at compile (http://localhost:15672/js/ejs-1.0.min.js:1:6654), :6:29) at EJS.render (http://localhost:15672/js/ejs-1.0.min.js:1:1885) at format (http://localhost:15672/js/main.js:1086:21) at check_login (http://localhost:15672/js/main.js:89:34) at start_app_login (http://localhost:15672/js/main.js:75:9) at HTMLDocument. (http://localhost:15672/js/main.js:3:5) at e (http://localhost:15672/js/jquery-3.4.1.min.js:2:29453) at t (http://localhost:15672/js/jquery-3.4.1.min.js:2:29755)

docker-compose up not working on Windows

When try to run docker compose, got following message
docker-compose up
WARNING: The PitStopAIKey variable is not set. Defaulting to a blank string.
ERROR: Volume sqlserverdata declared as external, but could not be found. Please create the volume manually using docker volume create --name=sqlserverdata and try again.

Question - EFCore migrations in production

Hi Edwin,

Awesome project! I have gained so much knowledge just reading through your codebase 👍

My question is around the database migrations and specifically where you are calling "Migrate" as part of creating the DbContext: Source

When doing a zero downtime deployment to production it would be standard to have some instances of this service on v1, and then some on v2 as things are roll out..

In that situation v2 would be trying to migrate the database.... but then the old v1 service would also be trying hard to migrate the database backwards which would cause some issues... 😢

In the recent past I have split out the migration exe into another project which I can call once explicitly as part of the deployment and make sure all database changes are backwards compatible to the previous release..

My question is - Am I missing something? Or is this something you haven't run into yet with PitStop so its not a concern yet..?

Any thoughts appreciated 👍

Deletion of resources

I have kind of a question, suppose I try to delete a customer from customermanagementapi service, should this service publish an event and delete the related customer's data from workshopmanagment database or they are not related in terms of record deletions.

Without customer data in master table in customermanagementapi, is it an appropriate approach to keep customer's data in workshopmanagment database?. If it is yes then shouldn't this introduces data inconsistency?

Thanks!

Add monitoring

The application could benefit from monitoring. Proposed product to use is Application Insights.

PSA: Create pitstop databases manually when deploying with azure sql

Not sure what the best place to post this is, but we noticed today that the 6 databases that are created when you start pitstop against an azure sql single-database server are created as vCore 2CPU a €500/m each 😅 (presumably because azure has no clue what you want when you ask it to create a database using SQL CREATE DATABASE commands and.. just picks the production tier to be safe).

Soo PSA: pre-provision your pitstop databases before deploying against azure sql!

Error while sending data through POST method

Hi @EdwinVW,

It is giving Error 500 while trying to POST data to workshop management service through swagger
UI. I have used the below sample data to POST where I have already registered customer with ID
IDs760480 and vehicle with License Number 703-64-800.

"date": "2023-07-20T00:00:00",
 "jobs": [
 {
 "id": "122d4e9f-ba3b-4279-91f0-04bd696724ba",
 "startTime": "2023-07-20T08:00:00",
 "endTime": "2023-07-20T10:00:00",
 "vehicle": {
 "licenseNumber": "703-64-800",
 "brand": "Kia",
 "type": "Convertible",
 },
 "customer": {
 "customerId": "IDs760480",
 "name": "Tonya Boyd",
 "telephoneNumber": "001-908-693-6629x6863"
 },
 "description": "Fix Engine issue",
 "actualStartTime": null,
 "actualEndTime": null,
 "notes": null,
 "status": "Planned"

If available, May I get exact format of some sample data available already to POST to workshop management service.

Thanks.

How do I

Hi,

In an event-driven autonomous microservice environment, how do I push data previously-stored in a database table "COMPANY" through RabbitMQ to a newly subscribed or created service with Database PRODUCT that has a copy of table "COMPANY" from COMPANY-Database?

Thanks in advance.

Issue with microsoft/mssql-server-linux:latest

docker-compose is not working for me today.
I tried several times and getting same error again and again as it is unable to pull microsoft/mssql-server-linux:latest
I tried it on other machine too.

docker-compose up -d

Pulling sqlserver (microsoft/mssql-server-linux:latest)... ERROR: manifest for microsoft/mssql-server-linux:latest not found: manifest unknown: manifest unknown

"topic" using in Infrasturcture.Message?

Hello Edwin, thank you very much for sharing this tutorial, I am not an expert to RabbitMQ but very exciting to learn. As I am research in this project where in Infrastructure.Messaging.IMessagePublisher, the method you defined as
Task PublishMessageAsync(string messageType, object message, string routingKey);
has an additional description param called
/// <param name="topic">Topic to publish the message to.</param>,
however I didn't see where you declare/implement this type of 'topic' anywhere through the Messaging, I also checked the tutorial through RabbitMQ - Topic , and found that difference by using 'fanout' vs 'direct(topic)', so in this project, I saw you're using 'fanout' through Message publisher, could you please let me know why using 'fanout' instead of 'direct/topic'? Seems to me that we can direct service type A to Process A, service type B to Process B which would be more like a 'direct' way.
Please feel free to let me know if I understand incorrectly. Thank you very much!

Future plan

I am wondering, if you could make those services which run on the background like time, invoice, notification, workshopmanagementeventhandler and audit into gRPC in future that would be more interesting!

Thanks,

Consistency between Db Entity and Event

I was wondering if there is a right approach to do this:

                  // insert customer
                    Customer customer = command.MapToCustomer();
                    _dbContext.Customers.Add(customer);
                    await _dbContext.SaveChangesAsync();

                    // send event
                    CustomerRegistered e = command.MapToCustomerRegistered();
                    await _messagePublisher.PublishMessageAsync(e.MessageType, e , "");

What happens if after you have called await _dbContext.SaveChangesAsync(); an error occurs when sending an event. Does it mean we will lose this event? Should we transactional outbox pattern here?

Running pods do not display webpage

Well I reached pretty much towards the end of the project outlines however I have been stuck almost at the finish line. I have configured all containers to Kubernetes and it works greatly, and finally trying to configure istio but somehow stuck and not sure what is the problem. I honestly followed all your steps as mentioned in wiki page and I choose ('method 2") installing istio and currently i have version 1.2.5 installed.

kubectl get pods -namespace

NAME                                          READY   STATUS             RESTARTS   AGE  
auditlogservicemanager-77bbf6795b-w5tpk       1/1     Running            0          12m  
customerapi-v1-597774488d-7xcwv               1/2     Running            0          12m  
invoiceservice-b8ff48f89-jz86l                1/1     Running            0          12m  
logserver-758d4598f6-g8b4x                    1/1     Running            0          12m  
mailserver-64444466b5-zpcmc                   1/1     Running            0          12m  
notificationservicemanager-5f57697696-gc5wf   1/1     Running            0          12m  
rabbitmq-66845d69cb-57dm7                     1/1     Running            0          12m  
sqlserver-7866c795f9-8vv9l                    1/1     Running            0          12m  
timeservice-5b67f48845-c5p4n                  1/1     Running            0          12m  
vehiclemanagementapi-7fbff9cbbf-llpx8         1/2     Running            0          12m  
web-78794b65cb-z58wh                          1/2     Running            0          12m  
workshopeventhandler-77db84d66d-9r8gv         1/1     Running            0          12m  
workshopmanagementapi-777447ddd8-vtc5w        0/2     CrashLoopBackOff   4          12m  

All of the pods are running except workshopmenagementapi getting crashed over and over again.

I am kind of confused here if you look at all the running pods except following has more than 1 pod but when i looked at your wiki page screen shot it has showing only 1/1 though all the configurations and settings are same as I followed exactly same steps as you mentioned.

NAME                                          READY   STATUS             RESTARTS   AGE 
customerapi-v1-597774488d-7xcwv               1/2     Running            0          12m 
vehiclemanagementapi-7fbff9cbbf-llpx8         1/2     Running            0          12m 
web-78794b65cb-z58wh                          1/2     Running            0          12m 
workshopmanagementapi-777447ddd8-vtc5w        0/2     CrashLoopBackOff   4          12m 

Problem descriptions:

When I test the application as stated in the wiki even though it was running fine in kubernetes clusters. None of pages are getting displayed basically istio can't display the localhost rather giving me following standard error page:

this page can't be reached.

therefore I tried to check the logs of these running pods and I have been able to extract following errors and I am not sure whether this is exactly the problem in relate to an error mentioned above :

kubectl describe pod -{podname} -namespace

Name:               web-78794b65cb-z58wh
Namespace:          auto
Priority:           0
PriorityClassName:  <none>
Node:               docker-desktop/192.168.65.3
Start Time:         Thu, 05 Sep 2019 14:35:05 +0530
Labels:             app=web
                    pod-template-hash=78794b65cb
                    system=auto
                    version=v1
Annotations:        sidecar.istio.io/status:
                      {"version":"761ebc5a63976754715f22fcf548f05270fb4b8db07324894aebdb31fa81d960","initContainers":["istio-init"],"containers":["istio-proxy"]...
Status:             Running
IP:                 10.1.2.72
Controlled By:      ReplicaSet/web-78794b65cb
Init Containers:
  istio-init:
    Container ID:  docker://a2341e6ac0f02537cbc5a47b6e23eee0a468c9d5edbfb5d0e832f8cef5343358
    Image:         gcr.io/istio-release/proxy_init:release-1.2-latest-daily
    Image ID:      docker-pullable://gcr.io/istio-release/proxy_init@sha256:129db113aadd8723e2cf80e1b1665cd404af57af563a49c880a56692688e07d9
    Port:          <none>
    Host Port:     <none>
    Args:
      -p
      15001
      -u
      1337
      -m
      REDIRECT
      -i
      *
      -x

      -b
      7000
      -d
      15020
    State:          Terminated
      Reason:       Completed
      Exit Code:    0
      Started:      Thu, 05 Sep 2019 14:35:18 +0530
      Finished:     Thu, 05 Sep 2019 14:35:20 +0530
    Ready:          True
    Restart Count:  0
    Limits:
      cpu:     100m
      memory:  50Mi
    Requests:
      cpu:        10m
      memory:     10Mi
    Environment:  <none>
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from default-token-7jgkh (ro)
Containers:
  web:
    Container ID:   docker://0f4399c834e38c97096c55031f0f13b4b4ce709221657b9497dcf0e7e4bc0738
    Image:          web:latest
    Image ID:       docker://sha256:1be5e1876e9c8167dceb6d0fed0047fbc2f4b972d18408e3f985b6004cb82340
    Port:           7000/TCP
    Host Port:      0/TCP
    State:          Running
      Started:      Thu, 05 Sep 2019 14:35:27 +0530
    Ready:          True
    Restart Count:  0
    Environment:
      ASPNETCORE_ENVIRONMENT:  Production
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from default-token-7jgkh (ro)
  istio-proxy:
    Container ID:  docker://d13f250851045fcdc586c39358a47e58ba01907fa8e4bf9ed2b729270c774f57
    Image:         gcr.io/istio-release/proxyv2:release-1.2-latest-daily
    Image ID:      docker-pullable://gcr.io/istio-release/proxyv2@sha256:750b3fa0400c74f9bad0b4ed19255b16913be8eb1693e7fabb6630ce4ef0a93b
    Port:          15090/TCP
    Host Port:     0/TCP
    Args:
      proxy
      sidecar
      --domain
      $(POD_NAMESPACE).svc.cluster.local
      --configPath
      /etc/istio/proxy
      --binaryPath
      /usr/local/bin/envoy
      --serviceCluster
      web.$(POD_NAMESPACE)
      --drainDuration
      45s
      --parentShutdownDuration
      1m0s
      --discoveryAddress
      istio-pilot.istio-system:15010
      --zipkinAddress
      zipkin.istio-system:9411
      --dnsRefreshRate
      300s
      --connectTimeout
      10s
      --proxyAdminPort
      15000
      --concurrency
      2
      --controlPlaneAuthPolicy
      NONE
      --statusPort
      15020
      --applicationPorts
      7000
    State:          Running
      Started:      Thu, 05 Sep 2019 14:35:33 +0530
    Ready:          False
    Restart Count:  0
    Limits:
      cpu:     2
      memory:  1Gi
    Requests:
      cpu:      100m
      memory:   128Mi
    Readiness:  http-get http://:15020/healthz/ready delay=1s timeout=1s period=2s #success=1 #failure=30
    Environment:
      POD_NAME:                          web-78794b65cb-z58wh (v1:metadata.name)
      POD_NAMESPACE:                     auto (v1:metadata.namespace)
      INSTANCE_IP:                        (v1:status.podIP)
      ISTIO_META_POD_NAME:               web-78794b65cb-z58wh (v1:metadata.name)
      ISTIO_META_CONFIG_NAMESPACE:       auto (v1:metadata.namespace)
      ISTIO_META_INTERCEPTION_MODE:      REDIRECT
      ISTIO_META_INCLUDE_INBOUND_PORTS:  7000
      ISTIO_METAJSON_LABELS:             {"app":"web","system":"auto","version":"v1"}

    Mounts:
      /etc/certs/ from istio-certs (ro)
      /etc/istio/proxy from istio-envoy (rw)
      /var/run/secrets/kubernetes.io/serviceaccount from default-token-7jgkh (ro)
Conditions:
  Type              Status
  Initialized       True
  Ready             False
  ContainersReady   False
  PodScheduled      True
Volumes:
  istio-envoy:
    Type:       EmptyDir (a temporary directory that shares a pod's lifetime)
    Medium:     Memory
    SizeLimit:  <unset>
  istio-certs:
    Type:        Secret (a volume populated by a Secret)
    SecretName:  istio.default
    Optional:    true
  default-token-7jgkh:
    Type:        Secret (a volume populated by a Secret)
    SecretName:  default-token-7jgkh
    Optional:    false
QoS Class:       Burstable
Node-Selectors:  <none>
Tolerations:     node.kubernetes.io/not-ready:NoExecute for 300s
                 node.kubernetes.io/unreachable:NoExecute for 300s
Events:
  Type     Reason     Age                    From                     Message
  ----     ------     ----                   ----                     -------
  Normal   Scheduled  23m                    default-scheduler        Successfully assigned auto/web-78794b65cb-z58wh to docker-desktop
  Normal   Pulled     23m                    kubelet, docker-desktop  Container image "gcr.io/istio-release/proxy_init:release-1.2-latest-daily" already present on machine
  Normal   Created    23m                    kubelet, docker-desktop  Created container istio-init
  Normal   Started    23m                    kubelet, docker-desktop  Started container istio-init
  Normal   Pulled     23m                    kubelet, docker-desktop  Container image "web:latest" already present on machine
  Normal   Created    23m                    kubelet, docker-desktop  Created container web
  Normal   Started    23m                    kubelet, docker-desktop  Started container web
  Normal   Pulled     23m                    kubelet, docker-desktop  Container image "gcr.io/istio-release/proxyv2:release-1.2-latest-daily" already present on machine
  Normal   Created    22m                    kubelet, docker-desktop  Created container istio-proxy
  Normal   Started    22m                    kubelet, docker-desktop  Started container istio-proxy
  Warning  Unhealthy  22m                    kubelet, docker-desktop  Readiness probe failed: Get http://10.1.2.72:15020/healthz/ready: dial tcp 10.1.2.72:15020: connect: connection refused
  Warning  Unhealthy  3m12s (x590 over 22m)  kubelet, docker-desktop  Readiness probe failed: HTTP probe failed with statuscode: 503

Therefore I am not quite sure as I have checked istio and kubernetes docs as well as stackoverflow but could not get the idea, and if you refer istio and kubernetes docs they are really painful most of them are bash commands I hardly seen any windows commands.

Therefore i would ask did i miss any settings or configurations which i amnot aware of even though i have gone through your wiki.

Thanks!

Event-sourcing and Event-storing

  1. Here in WorkshopManagementEventStore database you have saved the events as complete serialize json object in one column(EventData)
    Instead of that how about saving data in normalized form with proper multiple columns for each field/property?
    How and when should we chose saving events as serialized object over classical normalized data.
    Is it an standard practice to save events as a json object?

  2. I do understand about Event sourcing and Events Storing however i am not quite confident on that.
    Can you please share your brief thoughts in that context that how both("Event sourcing" and "Events Storing") are inter-related and how are different too.

Where WorkshopManagement database is created

Hi

I have one quick question that I can see where WorkshopManagementEventStore databse is being created but i am unable to locate where WorkshopManagement db is being created

// create database string sql = "IF NOT EXISTS(SELECT * FROM master.sys.databases WHERE name='WorkshopManagementEventStore') CREATE DATABASE WorkshopManagementEventStore;"; conn.Execute(sql);

Wrong handling of RabbitMQ messages

Hi Edwin!

Thanks a lot for the great work! Your solution is extreamly helpfull, basically for me it works as a textbook since I'm quite new in microservices development.

While implementing an integration with RabbitMQ I encountered a weird behavior when at some point messages started to pile up at RabbitMQ server without acknowledgement from a consumer. And on a consumer side I faced multiple DbUpdateConcurrencyException's.
It appears that since Consumer_Received method in RabbitMQMessageHandler class works actually asynchronously

if (await HandleEvent(ea))
{
...
}

then instead of simple EventingBasicConsumer an AsyncEventingBasicConsumer should be used.
You can find more details here: http://gigi.nullneuron.net/gigilabs/the-dangers-of-async-void-event-handlers/

Unfortunately I can't push my branch to this repo in order to create a pull request (due to 403).
So an updated file is attached to this post (I changed an extension to .txt, otherwise GitHub doesn't accept it).

Regards,
Dmitry

RabbitMQMessageHandler.txt

Reading Environment Variable Issue

Why all of console app only read Hosting environment to Production, even though you are running these apps on debug environment, which should be running on Development environment i supposed. Even though when you set aspnetcore_environment value to development on command line by running following command but that does not make any different either. Therefore how would i tell these console app that we are running on development environment, so runs on this environment.

Command Prompt: SETX ASPNETCORE_ENVIRONMENT "Development" (specific project folder)
Result : SUCCESS: Specified value was saved.  

Console display

Application started. Press Ctrl+C to shut down.
Hosting environment: Production

HostBuilder configuration

var hostBuilder = new HostBuilder()
                .ConfigureHostConfiguration(configHost =>
                {
                    configHost.SetBasePath(Directory.GetCurrentDirectory());
                    configHost.AddJsonFile("hostsettings.json", optional: true);
                    configHost.AddJsonFile($"appsettings.json", optional: false);
                    configHost.AddEnvironmentVariables();
                    configHost.AddEnvironmentVariables("DOTNET_");
                    configHost.AddCommandLine(args);
                })
                .ConfigureAppConfiguration((hostContext, config) =>
                {
                    config.AddJsonFile($"appsettings.{hostContext.HostingEnvironment.EnvironmentName}.json", optional: false);
                })

Launch settings

{
  "profiles": {
    "WorkShopEventHandler": {
      "commandName": "Project",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    }
  }
}

Projects are not configured in docker orchestrator support right now.

Maildev UI not opening in Browser

Hi EdwinVW

I have worked on running pitstop with docker-compose, Kubernetes etc on ubuntu arm64 and amd64 platform. Although it looks like with maildev image v1.2.0-beta1, the maildev UI doesn’t open while running through docker-compose. 

I had to do below mentioned changes in docker-compose.yml post that only the web-page of Maildev opened.

azureuser@Svm1:~/pitstop/src$ git diff docker-compose.yml  
diff --git a/src/docker-compose.yml b/src/docker-compose.yml  
index a2fe25a..67d004a 100644  
--- a/src/docker-compose.yml  
+++ b/src/docker-compose.yml  
@@ -26,11 +26,11 @@ services:  
       - SA_PASSWORD=8jkGh47hnDw89Haq8LN2  
   mailserver:  
-    image: maildev/maildev:1.1.0  
+    image: maildev/maildev:1.1.1  
     container_name: mailserver  
     ports:  
       - "25:25"  
-      - "4000:80"  
+      - "4000:1080" 

Also, with the above changes only UI of maildev gets opened in browser but I am not able to receive any email while testing for invoice and notifications.  

Please find below the steps to reproduce the issue: 

  1. Vim docker-compose.yml (do the changes mentioned above) 
  2. docker-compose up 
  3. Open maildev UI in browser http://localhost:4000/ 
  4. Follow the steps mentioned in wiki for testing notifications  
  5. Email should be received post 4th step but not receiving the same 

Please share your pointers as to how to resolve the same. Thanks in advance!

Invoice

Excerpt from testing application invoice service

The Invoice service reacts to the DayHasPassed event that is normally published by the Time service. But in order to speed this up, we'll publish such an event using the RabbitMQ Management Dashboard. See the description of how to do this under Testing Notifications above.

Getting error while sending invoice

Error while handling DayHasPassed event.

System.IO.DirectoryNotFoundException: Could not find a part of the path '/Assets/banner.jpg'.
   at Interop.ThrowExceptionForIoErrno(ErrorInfo errorInfo, String path, Boolean isDirectory, Func`2 errorRewriter)
   at Microsoft.Win32.SafeHandles.SafeFileHandle.Open(String path, OpenFlags flags, Int32 mode)
   at System.IO.FileStream.OpenHandle(FileMode mode, FileShare share, FileOptions options)
   at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize, FileOptions options)
   at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share)
   at System.Net.Mail.AttachmentBase.SetContentFromFile(String fileName, String mediaType)
   at System.Net.Mail.AttachmentBase..ctor(String fileName)
   at System.Net.Mail.Attachment..ctor(String fileName)
   at InvoiceService.InvoiceManager.SendInvoice(Customer customer, Invoice invoice) in /app/InvoiceManager.cs:line 255
   at InvoiceService.InvoiceManager.HandleAsync(DayHasPassed dhp) in /app/InvoiceManager.cs:line 146
   at InvoiceService.InvoiceManager.HandleMessageAsync(String messageType, String message) in /app/InvoiceManager.cs:line 65

Error when environment variable isn't set

When the environment variable isn't (correctly) set, the application tries to add a "appsettings..json" file which can obviously not be found.

Proposed change: default to production.

More platform independent development and build

First off thank you for this awesome project (and presentation you gave on the subject), it's really inspiring.
In my opinion this project should be truly platform independent. Of course it's all dotnetcore running inside docker on a (currently) linux kernel, optionally run on a Windows OS, but, here are some suggestions:

  • Allow to build without hard path references to a (Windows) filesystem
  • Allow a build using a docker-compose.yml file where not image:, but build: is used for self-built services, so you can do docker-compose build. That would make for an 'awesome platform independent oneliner'©.
  • If still required, provide .sh (bash) equivalents for the remaining PowerShell scripts
  • Instructions on development with Visual Studio Code, optionally with debugging enabled (if possible).
    I was trying to (docker) build and run everything without touching Visual Studio, but failed. Before creating a PR showing off the above suggested improvements, I first need to get around the COPY nuget /nuget step failing in each of the Dockerfile's.

Any suggestions on that (that require no Visual Studio)? 😄

Azure SQL is not supported

See: https://github.com/EdwinVW/pitstop/blob/master/src/NotificationService/Repositories/SqlServerNotificationRepository.cs#L39

DB_ID always returns NULL for azure sql (single database).

We could instead use

"IF NOT EXISTS(SELECT * FROM master.sys.databases WHERE name='Notification') CREATE DATABASE Notification;"

The USE command is also not allowed on azure sql single database which is used by ChangeDatabase: https://github.com/EdwinVW/pitstop/blob/master/src/NotificationService/Repositories/SqlServerNotificationRepository.cs#L44

We can replace this with closing the sql connection to master and creating a new sql connection to the target database.

This does work on azure sql. Would this change be acceptable?

WebApp not working on ARM / M1 pro CPU

I tried to run all services in a Kubernetes cluster on my Macbook with an m1 pro chip. I built all images locally, all services start up except the webapp service.
The pod is showing the following error:

Unhandled exception. System.IO.FileNotFoundException: Could not load file or assembly '/Pitstop.WebApp.dll'. The system cannot find the file specified.
File name: '/Pitstop.WebApp.dll'

There is a file with that exact name in the root directory of the container.
Running that file with dotnet after i exec into the container throws the same error.

The strange thing is that if i run dotnet publish -c Release -o out on my system (Not in a container) and then run the dll on my system the webapp will work as expected. So it's specifically not working in Docker it seems.

Event sourcing/storing with SAGA

(please correct me if i am wrong or something is missing)

Event sourcing helps in storing all the changes (events) to the system, rather than just its current/latest state, means we can persist different version(change history) for for any domain object.
So we can see the audit trail and or back track(roll back) to an early stage.

Questions:
(a)

So in future do you have any plan to use SAGA to demonstrate the roll back among multiple micro-services?

(b)
Kindly also explain the realtime usage of IsReplaying property

    public class WorkshopPlanning
    {
        /// <summary>
        /// Indication whether the aggregate is replaying events (true) or not (false).
        /// </summary>
        private bool IsReplaying { get; set; } = false;

and of course thanks again for your wonderful help and support - I am highly obliged and grateful to you!

Originally posted by @findkashif in #42 (comment)

Replace Angular front-end with a Blazor front-end

The current front-end is based on Angular. The PitStop front-end is a great showcase for building a Blazor application. Additionally, doing so would eliminate the need to keep the version of Angular up-to-date and have specific JavaScript / Angular knowledge for maintaining the front-end.

Stand-Alone SQL to build database

@EdwinVW
Would you mind posting a stand-along sql that builds out the database.

This is what I have so far, where some was derived from looking at code that relys on entity.


IF DB_ID('WorkshopManagement') IS NULL CREATE DATABASE WorkshopManagement;

IF DB_ID('CustomerManagement') IS NULL CREATE DATABASE CustomerManagement;
IF DB_ID('VehicleManagement') IS NULL CREATE DATABASE VehicleManagement;
IF DB_ID('WorkshopManagementEventStore') IS NULL CREATE DATABASE WorkshopManagementEventStore;
IF DB_ID('Invoicing') IS NULL CREATE DATABASE Invoicing;
IF DB_ID('Notification') IS NULL CREATE DATABASE Notification;

DROP TABLE IF EXISTS CustomerManagement.dbo.Customer;
if OBJECT_ID('CustomerManagement.dbo.Customer') IS NULL 
    CREATE TABLE CustomerManagement.dbo.Customer (
        [CustomerId] varchar(50) NOT NULL,
        [Name] varchar(50) NOT NULL,
        [Address] varchar(50) NOT NULL,
        [PostalCode] varchar(50) NOT NULL,
        [City] varchar(50) NOT NULL,
        [TelephoneNumber] varchar(50) NOT NULL,
        [EmailAddress] varchar(50) NOT NULL,
    PRIMARY KEY([CustomerId]));

DROP TABLE IF EXISTS VehicleManagement.dbo.Vehicle;
if OBJECT_ID('VehicleManagement.dbo.Vehicle') IS NULL 
    CREATE TABLE VehicleManagement.dbo.Vehicle (
        [LicenseNumber] varchar(50) NOT NULL,
        [Brand] varchar(50) NOT NULL,
        [Type] varchar(50) NOT NULL,
        [OwnerId] varchar(50) NOT NULL,
    PRIMARY KEY([LicenseNumber]));

DROP TABLE IF EXISTS WorkshopManagementEventStore.dbo.WorkshopPlanningEvent;
DROP TABLE IF EXISTS WorkshopManagementEventStore.dbo.WorkshopPlanning;

if OBJECT_ID('WorkshopManagementEventStore.dbo.WorkshopPlanning') IS NULL 
    CREATE TABLE WorkshopManagementEventStore.dbo.WorkshopPlanning (
        [Id] varchar(50) NOT NULL,
        [CurrentVersion] int NOT NULL,
    PRIMARY KEY([Id]));
    
if OBJECT_ID('WorkshopManagementEventStore.dbo.WorkshopPlanningEvent') IS NULL
    CREATE TABLE WorkshopManagementEventStore.dbo.WorkshopPlanningEvent (
        [Id] varchar(50) NOT NULL REFERENCES WorkshopManagementEventStore.dbo.WorkshopPlanning([Id]),
        [Version] int NOT NULL,
        [Timestamp] datetime2(7) NOT NULL,
        [MessageType] varchar(75) NOT NULL,
        [EventData] text,
    PRIMARY KEY([Id], [Version]));

DROP TABLE IF EXISTS Invoicing.dbo.Customer;
IF OBJECT_ID('Invoicing.dbo.Customer') IS NULL 
    CREATE TABLE Invoicing.dbo.Customer (
        CustomerId varchar(50) NOT NULL,
            Name varchar(50) NOT NULL,
            Address varchar(50),
            PostalCode varchar(50),
            City varchar(50),
        PRIMARY KEY(CustomerId));

DROP TABLE IF EXISTS Invoicing.dbo.MaintenanceJob;
IF OBJECT_ID('Invoicing.dbo.MaintenanceJob') IS NULL 
    CREATE TABLE Invoicing.dbo.MaintenanceJob (
        JobId varchar(50) NOT NULL,
        LicenseNumber varchar(50) NOT NULL,
        CustomerId varchar(50) NOT NULL,
        Description varchar(250) NOT NULL,
        StartTime datetime2 NULL,
        EndTime datetime2 NULL,
        Finished bit NOT NULL,
        InvoiceSent bit NOT NULL,
    PRIMARY KEY(JobId));

DROP TABLE IF EXISTS Invoicing.dbo.Invoice;
IF OBJECT_ID('Invoicing.dbo.Invoice') IS NULL 
    CREATE TABLE Invoicing.dbo.Invoice (
        InvoiceId varchar(50) NOT NULL,
        InvoiceDate datetime2 NOT NULL,
        CustomerId varchar(50) NOT NULL,
        Amount decimal(5,2) NOT NULL,
        Specification text,
        JobIds varchar(250),
    PRIMARY KEY(InvoiceId));

DROP TABLE IF EXISTS Notification.dbo.Customer;
IF OBJECT_ID('Notification.dbo.Customer') IS NULL 
    CREATE TABLE Notification.dbo.Customer (
        CustomerId varchar(50) NOT NULL,
        Name varchar(50) NOT NULL,
        TelephoneNumber varchar(50),
        EmailAddress varchar(50),
    PRIMARY KEY(CustomerId));

DROP TABLE IF EXISTS Notification.dbo.MaintenanceJob;
IF OBJECT_ID('Notification.dbo.MaintenanceJob') IS NULL 
    CREATE TABLE Notification.dbo.MaintenanceJob (
        JobId varchar(50) NOT NULL,
        LicenseNumber varchar(50) NOT NULL,
        CustomerId varchar(50) NOT NULL,
        StartTime datetime2 NOT NULL,
        Description varchar(250) NOT NULL,
    PRIMARY KEY(JobId));


Login failed for user 'sa'. Reason: Failed to open the explicitly specified database 'WorkshopManagementEventStore'. [CLIENT: 172.18.0.14]

Hi,thanks for this awesome project. I am new to all this microservices, docker and rabbitmq. Was thinking to use your youtube and this project as a startup for me to learn.

I followed your "Readme" section "Starting the application", and doing the docker-compose up. However I have issue on the error below.

2019-01-17 03:11:42.98 Logon Error: 18456, Severity: 14, State: 38.
2019-01-17 03:11:42.98 Logon Login failed for user 'sa'. Reason: Failed to open the explicitly specified database 'WorkshopManagementEventStore'. [CLIENT: 172.18.0.14]

The error logs like the login username/password failed for sa. But I have no idea how to SQL Server and check it. You mentioned:

The first time the services are started, the necessary databases are automatically created. You could check this by connecting to the SQL Server using SSMS (server localhost, port 1434; separate the server and port with a comma in SSMS: localhost,1434) ...........

I know that, sql server is now inside the docker container, and how should I access to it? By using my host sql server management studio and login to localhost,1434? Or?

Sorry to bother you, thanks a lot for helping.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.