Affinity can be used by those applications that need some control over which worker runs the action code of the process flow. For example, the code may need access to hardware/software that is installed on a limited set of workers, or a limited number of workers have a cache of information whose construction is expensive.
When the fabric is executing a process flow, it must locate a task service on which it will run the action. The default behavior of the fabric when locating a volunteer to run the action is specific to the type of task:
Unlimited tasks - executed on the local worker
exclusive - the fabric locates a worker with an available execlusive slot
limited - the fabric locates a worker that is running the limited task
Affinity introduces some user control over this process. For process flow states that specify affinity, the fabric executes user code (the "affinity method") on each worker in the fabric and uses information returned by the method to determine which worker is the best candidate. The process flow state's action is then executed on that worker.
Each state in the process flow can enable affinity by including either the task-affinity element (when the affinity method is described as a task), or the component-affinity element (when the affinity method is described in a component).
These elements:
selects the style (or type) of affinity, and
dictate the signature of the associated affinity method.
Note: affinity element cannot be used in states that invoke a sub-process (affinity can be applied to individual actions, but not to the whole sub-process flow).
The following table introduces the styles of affinity and the associated Process Flow XML. Following the table are code snippets in each of the supported languages showing the required method signatures that are required for each style.
Affinity Style
Description
None
The default. When no affinity element is used in the state, the fabric uses its default mechanism to locate workers (based on the type declared for the action: limited, exclusive, or unlimited).
The affinity method takes no parameters. The fabric calls the affinity method on each worker, and selected one worker whose affinity method returns "true" on which to run the action code.
The affinity method provides the fabric an integer rank. The fabric selects the "best fit" worker based on the rank of those affinity methods that return "true".
The affinity method is passed the data from one attribute of the current request, and the workers are ranked for "best fit".
Using Affinity in a Fabric Application
A completed fabric application using affinity will have:
a Process Flow that has one or more states that contain one of the affinity elements
user code that defines both action methods and affinity methods. The signatures of the affinity methods will be determined by the type of affinity selected in the process flow.
the affinity method(s) described in the task or component XML.
the action method(s) described in the task or component XML.
When designing the affinity method, remember that it will be run on each worker each time the state of the process flow is executed. Therefore, it should execute quickly (the time it takes is added to the overall latency of the process flow, and its overhead will be added to the CPU usage of every worker).
Affinity Rules for Exclusive Actions
When Affinity is with actions that use exclusivity, there are two potentially competing checks that rule out a given worker - the user's affinity method can return "false" or there may be no exclusive available slots on the worker. The fabric action for each of these cases:
The affinity style determines the action of the fabric in each of these cases (see the descriptions below for the specific handling).
Boolean (no-parameter) Affinity
Boolean Affinity should be used when the suitability of a worker can be determined from the current state of the worker. No information from the current request is needed to determine the suitability of the worker. For example, you might want to direct a request to only those workers with at least 2 gigabytes of memory.
This type of affinity is enabled when either the component-affinity or task-affinity is added to the process flow state with no nested elements. The affinity method must take no arguments and return a boolean (this will be validated for Java and C# at during packaging). The fabric will invoke the affinity method on each worker in the fabric. The fabric will select one worker whose affinity method returns true and run the state's action on that machine.
Boolean Affinity with Limited/Unlimited Actions.
resource-ready - the fabric executes the action on the first worker from which it receives an affirmative response.
no-resource - if no workers are found with the resource within the expected time, the fabric will take the "not-attempted" branch of the process flow.
Boolean Affinity with Exclusive Actions.
resource-ready - the fabric executes the action on the first worker that it finds with the resource that has an exclusive slot available.
resource-busy - if all workers that have the resource are busy, the fabric will wait for a worker to become available for busy_wait seconds. The busy_wait timeout defaults to INFINITE. The default can be overridden in the Task Module Definition XML.
no-resource - if no workers are found with the resource within the expected time, the fabric will take the "not-attempted" branch of the process flow.
The following example shows a process flow with boolean affinity enabled using the component-affinity element.
The corresponding Java component declaration is shown below. The class name is required and must identify a class that is deployed with the fabric application or associated far. See java-libs for more details.
The corresponding .NET task declaration is shown below. The method must be a member of the .NET class, and the class must exist in the assembly mentioned in file. The method tag is used here to alias the name of the method to that used in the process flow.
Resource affinity should be used when information from the current request is needed to determine the suitability of a worker. For example, the current request may have information about a particular city in North America. In order to perform work associated with a city, the worker must first do some time-consuming calculations that need to be performed only once per city. It would be advantageous to cache this information locally on the worker. Future work could be directed to the worker with the associated cache of information.
To use this style, create an affinity method that takes a single parameter. Populate the request key with the information needed by the affinity method. The type of the data in the request must be compatible with the type of the affinity method parameter. Add the method to the task or component XML and update the process flow state with the appropriate affinity element. The fabric will call the affinity method, passing the data from the request key and selecting a worker whose affinity method returns "true".
Resource Affinity with Limited/Unlimited Actions.
resource-ready - the fabric executes the action on the first worker from which it receives an affirmative response.
no-resource - if no workers are found with the resource within the expected time, the fabric will take the "not-attempted" branch of the process flow.
Resource Affinity with Exclusive Actions.
resource-ready - the fabric executes the action on the first worker that it finds with the resource that has an exclusive slot available.
resource-busy - if all workers that have the resource are busy, the fabric will wait for a worker to become available for busy_wait seconds. The busy_wait timeout defaults to INFINITE. The default can be overridden in the Task Module Definition XML.
no-resource - if no workers are found with the resource within the expected time, the fabric will take the "not-attempted" branch of the process flow.
The following example shows a process flow with resource affinity enabled using the component-affinity element.
The corresponding Java component declaration is shown below. The class name is required and must identify a class that is deployed with the fabric application or associated far. See java-libs for more details.
Ranked affinity is used when workers are capable of ranking their interest in performing the work. The fabric calls the affinity method on each worker, orders the responses based on the rank-type, and selects the best worker. For example, suppose workers maintain a cache of information and you want to direct new work to the worker with the smallest cache. The workers could rank their ability to process a request on the current size of their cache. This approach should be used to "level" the cached information across the workers of the fabric.
The rank style is enabled when the rank-argument element is added to the affinity method. No request data is passed to the affinity method. The method must define a single rank argument and a boolean return value. The fabric calls the method on each worker and accumulates the resulting ranks for all workers whose affinity method returns "true". The values are ordered and the best worker is selected.
There are two possible valuers for rank_type: minWeight and maxWeight. The fabric will select the worker returning the smallest rank and largest rank, respectively. Additional types will be added in future versions of the fabric.
Ranked Affinity with Limited/Unlimited Actions.
resource-ready - during the collection period, the fabric will collect responses. The affirmative responses are ordered, and the action is executed on the best-fit worker.
no-resource - if no workers are found with the resource within the collection period, the fabric will take the "not-attempted" branch of the process flow.
Ranked Affinity with Exclusive Actions.
resource-ready - during the collection period, the fabric will collect responses. The affirmative responses are ordered, and the action is executed on the best-fit worker.
resource-busy - if all workers that have the resource are busy, the fabric will wait for a worker to become available for busy_wait seconds. The busy_wait timeout defaults to INFINITE. The default can be overridden in the Task Module Definition XML.
no-resource - if no workers are found with the resource within the collection period, the fabric will take the "not-attempted" branch of the process flow.
The corresponding Java component declaration is shown below. The class name is required and must identify a class that is deployed with the fabric application or associated far. See java-libs for more details.
The outline of the corresponding Java class is shown below. To provide "out-parameter" semantics, Appistry has defined a simple wrapper class com.appistry.task.Rank that has a single rank property.
This style is a combination of Resource Affinity and Rank Affinity. Data from the request is used to parameterize the affinity method, and the responses will be ordered to select the best-fit worker. The affinity method must take two parameters (the resource data and the rank) and return a boolean value.
Ranked Resource Affinity with Limited/Unlimited Actions.
resource-ready - during the collection period, the fabric will collect responses. The affirmative responses are ordered, and the action is executed on the best-fit worker.
no-resource - if no workers are found with the resource within the collection period, the fabric will take the "not-attempted" branch of the process flow.
Ranked Resource Affinity with Exclusive Actions.
resource-ready - during the collection period, the fabric will collect responses. The affirmative responses are ordered, and the action is executed on the best-fit worker.
resource-busy - if all workers that have the resource are busy, the fabric will wait for a worker to become available for busy_wait seconds. The busy_wait timeout defaults to INFINITE. The default can be overridden in the Task Module Definition XML.
no-resource - if no workers are found with the resource within the collection period, the fabric will take the "not-attempted" branch of the process flow.
The corresponding Java component declaration is shown below. The class name is required and must identify a class that is deployed with the fabric application or associated far. See java-libs for more details.