This is documentation for Apprenda 7 and 8.
Documentation for older versions are also available.

WCF Service Tier

All Windows servers (with the exception of external nodes that may be hosting the Platform Load Manager or Platform Coordinator exclusively) that take part in your Platform are capable of hosting WCF services, though that doesn't necessarily mean all of them are used to host applications published to the instance. By default, WCF service deployments will not occur on servers hosting databases or user interfaces unless no other server is available. This preserves a separation of concerns for the servers on your grid, which is helpful on a production or production-like environment where servers have different hardware and software profiles. 

This page introduces what happens when the Platform deploys a WCF service and how the Platform facilitates communication between multiple service instances. Before continuing, you should understand how the Platform deploys applications, the fundamentals of application on the Platform, and the different Platform roles and services.

Deployment Mechanics

New service instances are created when any of the following actions occur:

  • An application is promoted to Sandbox or Published (and Scaling settings for the component are not set to "0")
  • A Platform Operator invokes the creation of a new instance via the System Operations Center.
  • The Development Team that published the service invokes the creation of a new instance via the Developer Portal, ACS or REST API (if permitted by the Platform Operator).
  • During a sweep to enforce Instance Count settings, the Platform finds that an instance count is below what is required by an existing setting.

When a new instance of the service is created, the following workflow is executed:

  1. The Platform Coordination service chooses an appropriate server.
  2. The Platform Coordination service asks the Service Container running on the chosen server to initiate the deployment of a new service.
  3. The Service Container generates a random GUID that will be known as the service instance ID.
  4. The Platform creates a local folder at C:\ApprendaPlatform\Container\LaunchPads\$serviceInstanceId (chosen from the root of C:\ to reduce the directory length from Windows' folder path length).
  5. The Service Container will copy the binaries consisting of that service from the Platform Repository to the local folder. However, existing Apprenda DLLs are not copied.
  6. The Service Container copies the Service Bootstrap and its dependencies (including the Apprenda Live API) from the repository into the local folder. This results in the executable Apprenda.WCFServiceHost.exe, which will host the service being created.
  7. The Service Bootstrap executable is configured appropriately, using your service's application configuration file as a base. This results in the generation of the file Apprenda.WCFServiceHost.exe.config. Among other things, the service is configured to work with the Platform, and any conditional configuration sections and tokens are changed to their appropriate "live" values. 
  8. The executable is launched in a separate process by the Service Container. The Apprenda service account configured during installation is used to launch the process.
  9. The Service Container registers with the Platform Coordination service that the new service instance is available.

Now that the service is running, it becomes available to fulfill requests.

Removal of Services

Service instances are removed from the grid when any of the following actions occur:

  • Faulty application code causes a crash.
  • The service exceeds the amount of memory it is permitted to use according to the service's assigned Resource Policy.
  • A Platform Operator invokes the removal of an existing instance via the System Operations Center.
  • During a sweep to enforce Instance Count settings, the Platform finds that an instance count is above what is required by an existing setting.
  • An application version is deleted or promoted/demoted to a different Lifecycle stage.
  • The application is deleted.

Platform Service Routing

The Platform maintains a sophisticated meta-typing system to help route service calls on the grid. This provides the following benefits:

  • Multiple versions of your service can be deployed on the same grid instance.
  • Services can be accessed via well-known names from outside of the grid via the Remote API.
  • Clients accessing the service from within the grid are configured to use Apprenda's Router as an intermediary, removing location awareness and providing service call completion guarantees.

Upon promotion of your application to the Sandbox and Published stages, the Platform catalogs details about your WCF service. Specifically, the Platform maintains an inheritance tree for versioning your services and to provide other system components with a way to logically reference them. For each WCF service, the Platform creates Service Types representing the abstract WSDL proposed by your service’s WCF Service Contract. As you evolve your application and service through the Platform’s versioning system, the Platform creates a new Service Implementation that is a concrete representation of the Service Type.

The identifiers are guaranteed to be unique, which allows the Platform to perform targeted, version-based routing and gives a uniquely identifiable logical system to target WCF service calls. Because of this, the Platform can guarantee clients that some instance of the service will satisfy a request without knowing the physical location of any instances. When you see Platform references (in documentation, portals, etc.) to metadata, it is typically referring to artifacts of this "typing system."

The following illustration shows the relationship between service types and Service Implementations as multiple versions of the service are created as the application evolves:

Each Service Implementation is linked directly to the WCF binaries that resulted in its creation. In fact, the Platform treats the Service Implementation as a synonym for the WCF service itself. Understanding this hierarchy is critical to understanding .NET service request dispatching in the Platform. The metadata defined at this stage creates a logical representation that the Platform uses to target arbitrary WCF service instances deployed on the grid. How this targeting and routing works is covered below.

Service Addressing

The Platform will configure all clients to point to the local Router, which runs on all Platform Windows servers, upon deployment. The following illustration indicates at a high level how service calls are routed on the grid.

Being a generic .NET service intermediary, the Router, upon receipt of the request, needs to determine what service the request is targeting. This is done via the Platform's service metadata. The Apprenda Router accepts logical service targets and, from a pool of available physical targets, translates those logical service targets to single specific physical targets.

All service calls in the Platform are logically addressed through the Apprenda Router. The Apprenda Router accepts SOAP messages via well-known URL patterns that inform the Router of the logical service target. The URL pattern is of the following specific format:

<scheme>://localhost[:port]/[listenPath/]<i|t>,<r|s>(<metaGUID>)

Each Apprenda Router starts a number of listeners waiting on requests matching this pattern; all adhering to the protocol will have a specific understanding of the URL parts after the ‘listenPath.’

  • <i|t>: specifies the type of logical target

    • i for 'Service Implementation'
    • t for a 'Service Type'
  • <r|s>: instructs the Router of the call style
    • r for ‘request/reply' meaning that the client expects a reply message
    • for a one-way ‘simplex’-style call
  • <metaGUID>: specifies the unique ID of the logical ‘Service Type’ or ‘Service Implementation’ target as defined via the first <i|t>

To help solidify an understanding of this pattern, consider the following example:

net.pipe://localhost/services/soap12/pipe/i,r(36b08605-e79c-46c4-ab9f-bc113ccb0a93)

This URL is targeting an Apprenda Router’s SOAP 1.2-named pipe listening port via the ‘listenPath’ ‘services/soap12/pipe.’ The client targeting this URL is expecting that the request will be handled by a service instance of the specific ‘Service Implementation’ (because of the ‘i') identified by the ID ‘36b08605-e79c-46c4-ab9f-bc113ccb0a93.’ Furthermore, because of the ‘r,’ the client is expecting that the request will generate a SOAP reply that the Apprenda Router has returned.

Targeting a ‘Service Type’ versus a ‘Service Implementation’ has implications. A ‘Service Implementation’ is a metadata leaf; no more specific logical representation exists. This means that a caller targeting a ‘Service Implementation’ can expect that a specific physical instance of the ‘Service Implementation’ will behaviorally manifest itself in a well-expected fashion since ‘Service Implementation’ maps 1-to-1 to a WCF class in a .NET assembly that defines very specific logic behind a WSDL contract. Targeting a ‘Service Type’ is not as concrete, since it simply acts as a WSDL abstraction that may have many specific implementations.

A request targeting a ‘Service Type’ is instead a request where selection of a more specific representation is left up to Apprenda. Every ‘Service Type’ keeps track of the ‘Service Implementation’ belonging to the newest version of the application owning the ‘Service Type’ as the default implementation. When the Router receives a request targeting a logical ‘Service Type,’ it will re-target the default ‘Service Implementation’ of that ‘Service Type.’

Having multiple ‘Service Implementations’ is important for allowing ‘Published’ and ‘Sandbox’ deployments for different versions of the same application to co-habit the same Platform. By having multiple ‘Service Implementations,’ the Platform can logically target different physical instances of different versions.

Service Routing and Availability

Circling back and following the path of a .NET service request originating from your client, the Router parses the targeted URL for the previously-described pattern, identifies the logical target, and checks its memory routing tables for the target. If the Apprenda Router has no address information for a physical instance matching the logical target specified, it immediately queries the Platform for a suitable service that is a representation of the logical criteria. If no service instance exists, the Router enters a "holding pattern," keeping the SOAP message in its in-memory pipeline and dispatches a dynamic deployment request to the service grid for an instance matching the targeted logical type.  Once the Apprenda Router is notified that an instance matching the targeted logical type has come online, it will flush the held message and add the new location information of the instance to its cache for future use.

The following illustration summarizes the workflow just described:

Besides offering an explanation of how service instances are located and automatically deployed to the grid, the previous explanation exemplifies one of the Platform's high-availability mechanisms. Not explicitly mentioned in the workflow description above is that the Platform will detect and attempt to re-start non-responsive services and will make multiple attempts to deploy services, all while holding your original service request noticeable to the client in the form of a delay in getting the response. 

Architectural Considerations

While these considerations are not necessarily linked to your application, it can be useful to know how the Platform architecturally provides routing.

the Platform’s architecture is based on decentralized peer-based routing. Rather than proving a single, centralized “be-all” service bus and SOAP router, the Platform runs local routing services on each individual server. Client proxies, when under the Platform’s management, are dynamically re-routed to logical targets rather than physical targets. All service requests are, through inter-process communication, pushed to the local Router service. The Router service then takes over dispatching as described earlier, targeting a well-known service. This architecture provides a number of key advantages:

  1. A better topological profile tightly aligning dispatch activity with client activity. Localized demands where certain “greedy” clients may be generating significant load only overload local services, and will not flood and starve a centralized shared Routing service. This allows for a better distribution of routing throughput based on point of origin. The Apprenda Router was built with the notion that it will typically share machine resources with its clients, so it was written to provide high throughput while minimizing its own requirements as much as possible.
  2. A higher level of overall resiliency when under duress. Decentralized architectures prove to be more resilient when taxed and can provide more consistent aggregate guarantees. Systems with centralized routers tend to bottleneck under high load, requiring significant scale-up and/or clustering.
  3. Lack of a risky central point of failure. Any failures can prove disastrous in a centralized routing system since the centralized dispatch services tend to be a “weakest link.” Instead, the Platform can ensure that failures are isolated to only certain parts of the network (affecting only local clients).

While there is seemingly a substantial overhead in adding this intermediary, care has been taken to optimize this process. Our performance testing shows that this is marginal after the first service request, and is minimal compared to the time to contact the target service itself.

Development Considerations

It is required that the Developer create fully-stateless services. Besides permitting deployment using the fully-shared model, this is important because the Platform may, as a part of its normal operation, direct service calls to a new service instance. One example of this is how the Platform's recoverability mechanics work: if a server with an instance of the service goes offline, the Platform will deploy a new instance to another machine automatically, as opposed to denying a service call.

See more about developing WCF Services for guest applications.

Deploying a .NET WCF Service with Multi-tenancy

In a traditional on-premises deployment, a WCF service would be deployed and serve the needs of a single Tenant. In the Platform, a service will be shared by multiple Tenants, and all calls for a service, regardless of which underlying Tenant originated the call, are handled by any instance of the service on the grid.​ the Platform's routing system will by default route service calls to all instances equally and randomly regardless of the underlying Tenant that makes the service call.