EnhancedOrgService – Enterprise-grade ServiceClient | Mage Series
At the core of Microsoft’s tooling library (Microsoft.PowerPlatform.Dataverse.Client
), there resides the out-of-the-box ServiceClient
class. It provides developers with the means to connect to the Power Platform easily and the convenience of some helper methods. On its own, the class is a perfect fit for small-scale applications, with a single purpose, and low throughput.
This leaves enterprise-grade applications in a bit of a pickle. Herein lies the opportunity to introduce a solution that preserves the integrity of the original design, but adds some critical enhancements for large-scale, heavy-hitting applications: EnhancedOrgService
.
TL;DR
- Microsoft’s libraries
OrganizationServiceProxy
has thread-safety issues- Causes serious random problems on high-load systems
- Replaced by the more robust
ServiceClient
some time ago ServiceClient
is slower in high-throughput applications
EnhancedOrgService
library- Greatly improves the performance of your application, and resolves safety issues
- Virtually indistinguishable and interchangeable with
IOrganizationService
- Includes many other cool features:
- Auto-retry, response caching, operation events and statistics
- Robust load balancer
- In-memory transactions, deferred execution, and fast-planned execution on the Power Platform server
- Install: here
- Quick connect:
var service = EnhancedServiceHelper.GetPoolingService("<connection-string>", <connection-count>);
Original Issue
Microsoft noticed an issue with the older version: OrganizationServiceProxy
, in that, it was problematic when it came to thread safety. Most notably, it caused random errors when multiple threads made calls to the Power Platform in parallel. The issues were notoriously hard to trace as well.
In the new library incarnation, Microsoft introduced a lock
around each internal channel access. This guaranteed that novice developers are unburdened by thread-safety concerns, which is in fact an advanced topic for most and requires some decent experience.
Locking to wait for an HTTP response is a major performance drawback, in this case. This is very evident when the ServiceClient
class is used in web services or high throughput applications; e.g. data migration.
Pooling Pattern
A slightly more experienced team would simply resolve the aforementioned issues by implementing a pooling pattern. In other words, their solution would maintain multiple connections in a pool, developers would request a connection from the pool to use and then release the connection to the pool when done.
This has to be done by each team individually in our community, and the solution must be thoroughly tested as it lies at the core of all logic, which could be catastrophic if an issue arises on Live.
EnhancedOrgService
EnhancedOrgService
is a custom library that acts as a common component for all ServiceClient
enhancements. It provides the following features:
- Automatic service pool handling (core feature)
- Connection warmup to improve initialisation performance (optional)
- Caching of operation results (optional)
- Automatic retry of failed operations (optional)
- Operation events and statistics
- Load balancer algorithms for multi-node environments
- In-memory transactions
- Deferred operations to run in a transaction
- Accumulate operations from across the application to be executed in one go
- Planned execution to be sent to the Power Platform for execution
- Return values from mid-execution operations can be used in later operations within the same transaction
I will go over the core features in this article, and then expand on the optional ones in later articles.
Let’s Automate
The library takes the pooling pattern a step further and tries to alleviate the whole thing off the developer’s shoulders. At the heart of the library lies automation logic for handling the aforementioned pooling control altogether. All the developer has to do is specify the number of services, and an internal pool is automatically created and managed by the library for maximum performance.
Installation
To install the library into a project, search for Yagasoft on NuGet, or access the page here.
Connecting to the Power Platform
Core Internal Components
There are a couple of components required for connection:
EnhancedServiceParams
: contains parameters that can be used to fine-tune a lot of aspects of the service and its operationsIEnhancedServiceFactory
: the source of the vanilla Power Platform connections and where theIEnhancedOrgService
object is createdIEnhancedServicePool
: implementation of the Object Pool pattern previously mentionedIEnhancedOrgService
: where all the internal pooling occurs and most of the features can be invoked
There are two basic approaches to creating a connection to the Power Platform in EnhancedOrgService
.
Implicit Factory Using Helpers
- Create the pool
- Request a simple connection/service
var pool = EnhancedServiceHelper.GetPool("<connection-string>"); var service = pool.GetService();
Explicit Factory
- Define the parameters
- Create a factory
- Create the pool
- Request a service
var parameters = new EnhancedServiceParams("<connection-string>"); var factory = new EnhancedServiceFactory<IEnhancedOrgService, EnhancedOrgService>(parameters); var pool = new EnhancedServicePool<IEnhancedOrgService, EnhancedOrgService>(factory); var service = pool.GetService();
This method is useful when finer control is required; e.g. cache control over the factory (explained in a later article). In addition, in the future, new service types might be introduced for extra choice by the developer.
Pool Management
Here, there are three basic methods of controlling the pool.
Implicit
This is a new addition to the library, and in my opinion, it’s the best way to go.
The pooling mechanics are fully managed. Using the service is identical to the out-of-the-box one.
Using helpers:
var service = EnhancedServiceHelper.GetPoolingService("<connection-string>");
Or manually:
var connectionString = "<connection-string>"; var pool = new DefaultServicePool(connectionString); var factory = new DefaultEnhancedFactory(connectionString); var service = factory.CreateService(pool);
Here, a ServiceClient
pool is created with a 5-connection limit, a quick factory is created, and then the service is requested with an internally managed pool defined earlier. There is no need to dispose of the service at all throughout its lifetime in this case, and no need to create any other service objects; only one service object is needed in the whole application.
The way it works is that whenever an internal operation needs to call the Power Platform, a connection is automatically requested from the pool, and then released back to the pool at the most optimal moment in the logic. This logic is completely transparent to the developer, and it guarantees that no starvation will occur.
Explicit
Simply, request a service from the pool, use it, and then dispose to return it to the pool.
This method might not fit the development style of some teams; check the ‘implicit’ method above, instead.
using (var service = pool.GetService()) { // code }
The biggest challenge is that the developer needs to decide on the best moment to dispose of the service: keep it in hand too long, and you starve other logic; forget to dispose of the service, and you end up exhausting the pool with an eventual deadlock.
Conclusion
This part was a quick introduction to the library. We went over the reason for its existence and its most important feature.
In the next part of the article, I will introduce more advanced features: load-balancing and API-limits handling.
1 Response
[…] To catch up, please read the first part here. […]