Giter Site home page Giter Site logo

gigya / microdot Goto Github PK

View Code? Open in Web Editor NEW
1.5K 104.0 228.0 19.91 MB

Microdot: An open source .NET microservices framework

License: Apache License 2.0

Batchfile 0.04% C# 99.96%
microservice orleans distributed-systems configuration service-discovery

microdot's Introduction

Microdot Framework

An open source .NET microservices framework

Microdot is an open source .NET framework that answers a lot of the needs for easily creating microservices.

Some of its main features:

  • Service container for hosting a microservice
  • Inter-service RPC for easy interface-based service communication
  • Client-side transparent response caching between services
  • Logging and Distributed Tracing support
  • Client-side load balancing and service discovery
  • Detailed health Checks for easy service monitoring
  • Hierarchical configuration system with online change detection
  • Dependency injection as first-class citizen
  • Orleans integration for creating Orleans based services and enjoying the benefits of virtual actors

Read on for an overview of the framework, and check the wiki for more details and a tutorial for building your first service.

Details

The Microdot framework helps you to create scalable and reliable microservices (a "microservice chassis"), allowing you to focus on writing code that defines the logic of your service without the need to tackle the myriad of challenges of developing a distributed system.

Microdot also plays nicely with the Orleans virtual actors framework, allowing you to easily write Orleans based microservices.

Microdot implements and supports many established Microservice-related patterns. Below is a comprehensive diagram created by Chris Richardson of Microservices.io, with added color highlights to show which parts are implemented in Microdot (yellow), which are planned to be implemented (purple) and which patterns are not implemented but can be easily incorporated (blue).

Microdot supported patterns

Microservices.io contains a lot of useful and well-written information about the microservice pattern/architecture and the difficulties of implementing it correctly. If you are new to this architecture, it can help get you up to speed quickly and will likely help you utilize Microdot to its fullest.


Features

  • A service container which accepts command-line parameters that define how your service runs, e.g. as a command-line process or a Windows Service, with or without console logs, the port your service will use to listen to incoming requests, whether it runs alone or as part of a cluster (and the cluster name to join), and whether it should shut down gracefully once a monitored parent PID exits. Sensible defaults are used based on your build configuration (Release/Debug).
  • inter-service RPC allowing services to call one another. Each service exposes one or more C# interfaces, and clients call it by receiving an instance of an interface that performs transparent RPC using JSON over HTTP. This includes client-side load balancing (no need for a load balancer in front of your service), failover support, and secure comunication via HTTPS with certificates validations for sensitive services, if needed.
  • Client-side, opt-in, transparent response caching between services. Useful to reduce end-to-end latency when many of your services rely on a few core services that serve relatively static data that is allowed to be eventually consistent. Also useful to reduce the impact of said services failing, while their responses are still cached by clients.
  • Logging and Distributed Tracing facilities to help diagnosing issues in production, such as Exception Tracking. Client- and server-side events are emitted for every call and can be used to trace how a request was handled across all services (the call tree), and the latency each one contributed.
  • Client-side Service discovery that supports HashiCorp's Consul or manual configuration-based discovery.
  • All components emit performance metrics via Metrics.NET for real-time performance monitoring.
  • Detailed Health Checks are provided for each subsystem, and can easily be extended to cover your service's external dependencies.
  • A hierarchical configuration system based on XML files which allows overriding values based on where and how the microservice is hosted (per data center, environment and microservice). The configuration is consumed from code via strongly-typed objects with automatic mapping and is refreshed at real time when XML files change.
  • Highly modular design and first-class dependency injection support using Ninject, allowing you to swap out every component with your own implementation if needed.
  • Tools to help test your service, for Unit Tests, Service Component Tests and Service Integration Contract Test.

Orleans integration

Microdot provides integration with Microsoft Orleans which, in turn, provides:

  • Ease of development - A simple programming model (Virtual Actors) that relieves you from dealing with threads, locks, mutexes, transactions, distrubuted state consistency, etc.
  • Scale up - write async code and utilize all the power your machine has; only one thread per CPU core, cooperative multitasking and async IO. The result is high-throughput, low-latency, low-overhead services.
  • Scale out - Without any changes to your code, you can scale your service to any number of nodes without service interruption.
  • Resiliency - failure of a node only affects in-flight operations happening on that node, but your service remains operational and work is redistributed across healthy nodes. Orleans also gracefully handles situations like multiple node failure, split brain and other disasters.
  • Low latency and disk I/O - by automatically caching your most active business entities, so they don't need to be loaded from disk when their state needs to be read.

You may choose to implement your micro-services over Orleans or not (or just some of them). In general, you're probably better off using Orleans, but in certain cases you might want not to, e.g. if you have a stateless service that requires no internal consistency or coordination -- such as an API gateway, a repository on top of a database (that handles the concurrency), pure functions such as complex calculations, image or document processing or generation, or a proxy service to external systems.

The rest of this document uses Orlean jargon such as grains and silos. It is highly recommended to familiarize yourself with those basic concepts by reading this short introduction to Orleans.


Getting started

The easiest way to start using Microdot is by adding the Gigya.Microdot.Orleans.Ninject.Host NuGet to a Console Application C# project. This will also install its dependencies, which includes everything you need to build your service. Then will need to:

  • Create your service host that will run your service
  • Define your public-facing service interface. Methods on that interface can be called from outside.
  • Define your stateless-worker service grain and interface that implement the public-facing interface.
  • Define any other grains you need to perform the required processing.
  • Run your service (F5)

A detailed step-by-step guide is available here.


Architecture

This section details the architecture of Microdot at a high level, without going into too many details.

System Architecture

Microdot System Architecture Diagram

A service (green) is composed of several nodes, each one is a Microdot host (blue) that is running an Orleans Silo (purple). The host accepts RPC calls via JSON over HTTP and forwards it to the Silo. Calls to the host can come from clients (yellow), e.g. frontend, or from other services. Each Orleans Silo is part of an Orleans cluster, and every Silo communicate with other silos in the cluster using a propriatary binary communication protocol. Each Silo in an Orleans cluster also connects to a Membership Table (e.g. ZooKeeper, Consul, Azure or other high-availability database), which it uses to discover other Silos in the same cluster (not shown in diagram).


Node Architecture

Microdot Node Architecture Diagram

Each node is composed of a Microdot host which contains three main components: HttpServiceListener (dark blue), Service Grain (orange) and other grains (white).

  • HttpServiceListener is responsible for listening to incoming HTTP requests, parsing them and calling the appropriate method on the Service Grain.
  • The Service Grain is responsible for exposing and handling the public API of your service. It will receive calls from the HttpServiceListener and needs to do initial processing on them and usually dispatch them to other grains. It is required by the Microdot framework, and is treated as the entry point of your service.
  • All the other grains are responsible for the core functions of your service. Most, if not all of your service's logic will reside in those grains. The methods on these grains are not exposed via by Microdot and can only be called from within that service (except when using an Orleans feature, 'Outside Grain Client', in which case it is possible to call any grain directly using Orlean's binary communication protocol, but this can be blocked if desired).
  • The Service Interface, an ordinary .NET interface that defines the public-facing API of your service, is published via NuGet (usually an internal server) so that other client can call your service (e.g. other services, frontend/GUI, DevOps tools, etc).
  • The Service Interface NuGet is used by client in conjunction with the ServiceProxy, which generates (at runtime) a client that implements that interface. Any calls to the client are transformed into JSON that contains which method was called, the arguments that were passed to the method and additional tracing data. The JSON is sent to the service over HTTP (the hostname, port and protocol are resolved using Service Discovery) and the remote service returns a JSON representing the return value of the method, which is deserialized and returned to the caller of the ServiceProxy.

microdot's People

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  avatar

microdot's Issues

Fix compiler warnings

Currently when compiling Microdot, the compiler give 26 warnings. These should be fixed or suppressed.

  • Warning CS1574 XML comment has cref attribute 'HttpServiceAttribute' that could not be resolved Gigya.Microdot.Hosting C:\Git\Microdot\Gigya.Microdot.Hosting\HttpService\IServiceEndPointDefinition.cs 52 Active
  • Warning CS1574 XML comment has cref attribute 'GigyaServiceHost' that could not be resolved Gigya.Microdot.SharedLogic C:\Git\Microdot\Gigya.Microdot.SharedLogic\ServiceArguments.cs 185 Active
  • Warning CS1574 XML comment has cref attribute 'HttpServiceAttribute' that could not be resolved Gigya.Microdot.Hosting C:\Git\Microdot\Gigya.Microdot.Hosting\HttpService\ServiceMethod.cs 39 Active
  • Warning CS0618 'Thread.Suspend()' is obsolete: 'Thread.Suspend has been deprecated. Please use other classes in System.Threading, such as Monitor, Mutex, Event, and Semaphore, to synchronize Threads or protect resources. http://go.microsoft.com/fwlink/?linkid=14202' Gigya.Microdot.Hosting C:\Git\Microdot\Gigya.Microdot.Hosting\Service\GigyaServiceHost.cs 286 Active
  • Warning CS0618 'StackTrace.StackTrace(Thread, bool)' is obsolete: 'This constructor has been deprecated. Please use a constructor that does not require a Thread parameter. http://go.microsoft.com/fwlink/?linkid=14202' Gigya.Microdot.Hosting C:\Git\Microdot\Gigya.Microdot.Hosting\Service\GigyaServiceHost.cs 288 Active
  • Warning CS0168 The variable 'ex' is declared but never used Gigya.Microdot.Hosting C:\Git\Microdot\Gigya.Microdot.Hosting\Service\GigyaServiceHost.cs 291 Active
  • Warning CS0618 'Thread.Resume()' is obsolete: 'Thread.Resume has been deprecated. Please use other classes in System.Threading, such as Monitor, Mutex, Event, and Semaphore, to synchronize Threads or protect resources. http://go.microsoft.com/fwlink/?linkid=14202' Gigya.Microdot.Hosting C:\Git\Microdot\Gigya.Microdot.Hosting\Service\GigyaServiceHost.cs 294 Active
  • Warning CS1998 This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread. Gigya.Microdot.Orleans.Hosting.FunctionalTests C:\Git\Microdot\tests\Gigya.Microdot.Orleans.Hosting.FunctionalTests\Microservice\CalculatorService\CalculatorWorkerGrain.cs 76 Active
  • Warning CS1998 This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread. Gigya.Microdot.Orleans.Hosting.FunctionalTests C:\Git\Microdot\tests\Gigya.Microdot.Orleans.Hosting.FunctionalTests\Microservice\CalculatorService\CalculatorWorkerGrain.cs 88 Active
  • Warning CS1998 This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread. Gigya.Microdot.Orleans.Hosting.FunctionalTests C:\Git\Microdot\tests\Gigya.Microdot.Orleans.Hosting.FunctionalTests\Microservice\CalculatorService\CalculatorWorkerGrain.cs 95 Active
  • Warning CS1998 This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread. Gigya.Microdot.Orleans.Hosting.FunctionalTests C:\Git\Microdot\tests\Gigya.Microdot.Orleans.Hosting.FunctionalTests\Microservice\CalculatorService\CalculatorWorkerGrain.cs 102 Active
  • Warning CS1998 This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread. Gigya.Microdot.Orleans.Hosting.FunctionalTests C:\Git\Microdot\tests\Gigya.Microdot.Orleans.Hosting.FunctionalTests\Microservice\CalculatorService\CalculatorWorkerGrain.cs 104 Active
  • Warning CS1998 This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread. Gigya.Microdot.Orleans.Hosting.FunctionalTests C:\Git\Microdot\tests\Gigya.Microdot.Orleans.Hosting.FunctionalTests\Microservice\CalculatorService\CalculatorWorkerGrain.cs 106 Active
  • Warning CS1998 This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread. Gigya.Microdot.Orleans.Hosting.FunctionalTests C:\Git\Microdot\tests\Gigya.Microdot.Orleans.Hosting.FunctionalTests\Microservice\ProgrammableHealthGrain.cs 43 Active
  • Warning CS1998 This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread. Gigya.Microdot.Orleans.Hosting.FunctionalTests C:\Git\Microdot\tests\Gigya.Microdot.Orleans.Hosting.FunctionalTests\Microservice\ProgrammableHealthGrain.cs 50 Active
  • Warning CS0169 The field 'Data.s' is never used Gigya.Microdot.ServiceContract.UnitTests C:\Git\Microdot\tests\Gigya.Microdot.ServiceContract.UnitTests\ServiceSchemaTests.cs 34 Active
  • Warning CS0169 The field 'Data.n' is never used Gigya.Microdot.ServiceContract.UnitTests C:\Git\Microdot\tests\Gigya.Microdot.ServiceContract.UnitTests\ServiceSchemaTests.cs 35 Active
  • Warning CS0169 The field 'Nested.time' is never used Gigya.Microdot.ServiceContract.UnitTests C:\Git\Microdot\tests\Gigya.Microdot.ServiceContract.UnitTests\ServiceSchemaTests.cs 40 Active
  • Warning CA1063 Provide an overridable implementation of Dispose(bool) on 'CustomTimings' or mark the type as sealed. A call to Dispose(false) should only clean up native resources. A call to Dispose(true) should clean up both managed and native resources. Gigya.Microdot.SharedLogic C:\Git\Microdot\Gigya.Microdot.SharedLogic\Measurement\CustomTimings.cs 28 Active
  • Warning CA1063 Modify 'CustomTimings.Dispose()' so that it calls Dispose(true), then calls GC.SuppressFinalize on the current object instance ('this' or 'Me' in Visual Basic), and then returns. Gigya.Microdot.SharedLogic C:\Git\Microdot\Gigya.Microdot.SharedLogic\Measurement\CustomTimings.cs 79 Active
  • Warning CA1063 Provide an overridable implementation of Dispose(bool) on 'ComponentHealthMonitor' or mark the type as sealed. A call to Dispose(false) should only clean up native resources. A call to Dispose(true) should clean up both managed and native resources. Gigya.Microdot.SharedLogic C:\Git\Microdot\Gigya.Microdot.SharedLogic\Monitor\ComponentHealthMonitor.cs 29 Active
  • Warning CA1063 Modify 'ComponentHealthMonitor.Dispose()' so that it calls Dispose(true), then calls GC.SuppressFinalize on the current object instance ('this' or 'Me' in Visual Basic), and then returns. Gigya.Microdot.SharedLogic C:\Git\Microdot\Gigya.Microdot.SharedLogic\Monitor\ComponentHealthMonitor.cs 87 Active
  • Warning CA2214 'IdentityServiceInterfaceMapper.IdentityServiceInterfaceMapper(Type[])' contains a call chain that results in a call to a virtual method defined by the class. Review the following call stack for unintended consequences:
  • IdentityServiceInterfaceMapper..ctor(Type[])
  • ServiceInterfaceMapper.set_ServiceInterfaceTypes(IEnumerable):Void Gigya.Microdot.Hosting C:\Git\Microdot\Gigya.Microdot.Hosting\HttpService\IdentityServiceInterfaceMapper.cs 36 Active
  • Warning CA2213 'GigyaServiceHost' contains field 'GigyaServiceHost.k__BackingField' that is of IDisposable type: 'ManualResetEvent'. Change the Dispose method on 'GigyaServiceHost' to call Dispose or Close on this field. Gigya.Microdot.Hosting C:\Git\Microdot\Gigya.Microdot.Hosting\Service\GigyaServiceHost.cs 253 Active
  • Warning CA2213 'ServiceProxyProvider' contains field 'ServiceProxyProvider._httpMessageHandler' that is of IDisposable type: 'HttpMessageHandler'. Change the Dispose method on 'ServiceProxyProvider' to call Dispose or Close on this field. Gigya.Microdot.ServiceProxy C:\Git\Microdot\Gigya.Microdot.ServiceProxy\ServiceProxyProvider.cs 526 Active
  • Warning CA1001 Implement IDisposable on 'HttpLog' because it creates members of the following IDisposable types: 'HttpClient'. If 'HttpLog' has previously shipped, adding new members that implement IDisposable to this type is considered a breaking change to existing consumers. Gigya.Microdot.Fakes C:\Git\Microdot\Gigya.Microdot.Fakes\HttpLog.cs 36 Active

Cannot build Microdot Solution

I downloaded source code of Microdot and I tried to compile solution.
I got exception while paket tries to download Gigya.OrleansDashboard.NetStandard 3.0.8.

Here is message:

Downloading Gigya.OrleansDashboard.NetStandard 3.0.8
Source 'http://nuget.gigya.net/nugetForVS/nuget' exception: System.Exception: Could not retrieve data from 'http://nuget.gigya.net/nugetForVS/nuget/FindPackagesById()?semVerLevel=2.0.0&id='Gigya.OrleansDashboard.NetStandard'' ---> System.Net.Http.HttpRequestException: An error occurred while sending the request. ---> System.Net.WebException: The remote name could not be resolved: 'nuget.gigya.net'
at System.Net.HttpWebRequest.EndGetResponse(IAsyncResult asyncResult)
at System.Net.Http.HttpClientHandler.GetResponseCallback(IAsyncResult ar)
--- End of inner exception stack trace ---
at [email protected](Exception _arg1)
at [email protected](AsyncParams1 args) --- End of inner exception stack trace --- at [email protected](Exception _arg3) at [email protected](AsyncParams1 args)
Something went wrong while downloading Gigya.OrleansDashboard.NetStandard 3.0.8
Message: Could not download Gigya.OrleansDashboard.NetStandard 3.0.8.

I was able to work with version 3.0.5. My currently downloaded version is 3.1.6.

how to use consul in microdot?

I have downloaded the GpuService sample, and then change some Environments, but got some error running GpuService.Client

// an empty file loadPaths.json
Environment.SetEnvironmentVariable("GIGYA_CONFIG_ROOT", @"D:\test\dotnet\microdot-samples\GpuService\");
Environment.SetEnvironmentVariable("ENV", "dev");
// consul
Environment.SetEnvironmentVariable("CONSUL", "127.0.0.1:8500");

consul service defination

{
  "service": {
    // can not find a way to change service name(default to GpuService-)
    "name": "GpuService-dev",
    "port": 10000
  }
}

errors

System.AggregateException: One or more errors occurred. ---> Gigya.Common.Contra
cts.Exceptions.EnvironmentException: Query not exists on Consul. See tags for de
tails.; requestedService=GpuService-dev, consulAddress=http://127.0.0.1:8500/, r
equestTime=0001-01-01 00:00:00.000, requestLog=, responseLog=, queryDefined=Fals
e, consulError=

is there any documents i can refer to?

Help with inventory sample

I am new to microdot. I am trying to run sample inventory service.
I managed it after a while. Now I am trying to run the inventory service client, but I got exception at startup. I have no idea why.
Here is what I got:
System.NullReferenceException
HResult=0x80004003
Message=Object reference not set to an instance of an object.
Source=Gigya.Microdot.ServiceProxy
StackTrace:
at Gigya.Microdot.ServiceProxy.ServiceProxyProvider.GetConfig()
at Gigya.Microdot.ServiceProxy.ServiceProxyProvider.d__80.MoveNext()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Gigya.Microdot.ServiceProxy.ServiceProxyProvider.d__79.MoveNext()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
at InventoryService.Client.FortuneCookieTrader.d__10.MoveNext() in D:\Limos\Downloads\microdot-samples-master\microdot-samples-master\InventoryService\InventoryService.Client\FortuneCookieTrader.cs:line 31

This exception was originally thrown at this call stack:
[External Code]
InventoryService.Client.FortuneCookieTrader.Start() in FortuneCookieTrader.cs

.NET core porting

Hi,
We have an up coming requirement in doing MicroServices in .NET core 2.0. What is the time line by which the .NET core port will be available.

Thanks and regards
Venkatesh

About the value of ConsulEndPoint.HostName

the namespace Gigya.Microdot.ServiceDiscovery
class ConsulClient
line: 494
var endpoints = nodes.Select(ep => new ConsulEndPoint { HostName = ep.Node.Name, Port = ep.Service.Port, Version = GetEndpointVersion(ep) }).OrderBy(x => x.HostName).ThenBy(x => x.Port).ToArray();
why HostName = ep.Node.Name and not ep.Node.Address or ep.Service.Address?

Service Discovery: Per-method call and cache timeouts

Problem: There might be a need to change cache TTLs for specific methods in deployed services (e.g. production) via configuration, or to disable them outright. After modifying the Caching proxy to support TTL per method, there isn't any way to configure it.

Problem: Similarly, devs want to be able to define individual timeouts per service method. For example, methods that rely on DB will be allowed longer timeouts.

Proposed solution: Add a new configuration that allows changing both the request and caching TTLs and disabling the caching for any specific method. This configuration should reside close to service discovery configuration. This implies we could define per-client TTLs.

Does it load balance?

Team,
Do you any documentation over Load balancing? If not, could you please give a high level flow.

Thanks

Is this project still maintained

We're considering using this framework as it would provide more structure to our project but it does not seems really maintained.
DId you migrate to dotnet core?

Status on .NET Core

Hello!

I wanted to know whether you plan supporting .NET Core soon.

Thanks!

Cannot build

I have tried to build the package with VS2015 and VS2017.
In both cases many errors.
What I am doing wrong?

ServiceProxyProvider

looking at our stats looks like the network time is unjustified long, for example, a random query of one minute:

target.service target.method MAX(stats.network.time)
UserIdService TryGetUserIds 665.7730102539062
PolicyService GetEffectiveSitePolicy 132.62899780273438
SitesService GetSite 230.61199951171875

other stats of the service doesn't indicate any issues so I was searching for some time-consuming logic between
RequestStartTimestamp marking and the actually httpClient.PostAsync and I have some concerns about this piece of code:

private (HttpClient httpClient, bool isHttps) GetHttpClient(ServiceDiscoveryConfig serviceConfig, DiscoveryConfig defaultConfig, bool tryHttps, string hostname, int basePort)
{
var forceHttps = serviceConfig.UseHttpsOverride ?? (ServiceInterfaceRequiresHttps || defaultConfig.UseHttpsOverride);
var useHttps = tryHttps || forceHttps;
string securityRole = serviceConfig.SecurityRole;
var verificationMode = serviceConfig.ServerCertificateVerification ??
defaultConfig.ServerCertificateVerification;
var supplyClientCertificate = (serviceConfig.ClientCertificateVerification ?? defaultConfig.ClientCertificateVerification)
== ClientCertificateVerificationMode.VerifyIdenticalRootCertificate;
var httpKey = new HttpClientConfiguration(useHttps, securityRole, serviceConfig.RequestTimeout, verificationMode, supplyClientCertificate);
lock (HttpClientLock)
{
if (LastHttpClient != null && LastHttpClientKey.Equals(httpKey))
return ( httpClient: LastHttpClient, isHttps: useHttps);
// In case we're trying HTTPs and the previous request on this instance was HTTP (or if this is the first request)
if (Not(forceHttps) && httpKey.UseHttps && Not(LastHttpClientKey?.UseHttps ?? false))
{
var now = DateTime.Now;
if (now - _lastHttpsTestTime > _httpsTestInterval)
{
_lastHttpsTestTime = now;
RunHttpsAvailabilityTest(httpKey, hostname, basePort);
}
httpKey = new HttpClientConfiguration(
useHttps: false,
securityRole: null,
timeout:httpKey.Timeout,
verificationMode:httpKey.VerificationMode,
supplyClientCertificate: httpKey.SupplyClientCertificate);
}
if (!(LastHttpClientKey?.Equals(httpKey) ?? false))
{
var messageHandler = _httpMessageHandlerFactory(httpKey);
var httpClient = CreateHttpClient(messageHandler, httpKey.Timeout);
LastHttpClient = httpClient;
LastHttpClientKey = httpKey;
_httpMessageHandler = messageHandler;
}
return (httpClient: LastHttpClient, isHttps: httpKey.UseHttps);
}
}

  • in case of ServerCertificateVerification or ClientCertificateVerification configured, this lock contains inside the certificate loading which can take time, and we are syncly blocking any attempts to call the service which probably the intention, but what happens to the thread during this lock?

    clientCert = CertificateLocator.GetCertificate("Client");

    var store = new X509Store(storeName, storeLocation);
    store.Open(OpenFlags.OpenExistingOnly | OpenFlags.ReadOnly);

  • is it possible that async cache refresh is "syncly" waiting for this lock?

    existingItem.RefreshTask = ((Func<Task>)(async () =>
    {
    try
    {
    var getNewValue = WrappedFactory(false);
    await getNewValue.ConfigureAwait(false);
    existingItem.CurrentValueTask = getNewValue;
    existingItem.NextRefreshTime = DateTime.UtcNow + policy.RefreshTime;
    MemoryCache.Set(new CacheItem(key, existingItem), policy);
    }
    catch
    {
    existingItem.NextRefreshTime = DateTime.UtcNow + policy.FailedRefreshDelay;
    }
    })).Invoke();

  • in case of an unreachable error or any type of 'HTTP request exception', we are repeating the process but with tryHttps=false, I'm not sure I completely understood the flow, this is what I see:


    • what am I missing here?
    • are we performing every HTTP request twice?
    • are we creating two new HTTP clients for every request?
    • are we disposing all of these clients and handlers?
    • this happens every reachability check, plus to calls attempts?
    • what will happen when we are running parallel requests to the same service, even without the certificate, creating an HTTP client and handler is not the cheapest code, and do it each request and within a lock statement sounds expensive.

** see creating multiple HTTP clients effect

.NET Core 2.0?

Is it possible to use microdot with .NET Core 2.0 instead of Framework 4.7?

Update to .net 4.6.1

Framework should be move to a modern platform to be in alignment with Orleans 1.5

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.