This section discusses some Sentinel feature development Best Practices |
This page documents and describes some of the Best Practices established by the Sentinel development team.
For each guideline this page discusses why the practice should be followed, and whether there are situations when it may not be appropriate to follow the guideline. While there are existing features that do not follow all these guidelines, new features should be written to follow the instructions on this page.
Effective Tracing
Trace messages serve a number of purposes. Trace messages at fine
, finer
and finest
should be used when diagnosing
a problem. Trace messages at warning
and severe
should be used to record information related to a situation that will
cause unexpected behaviour when it happens. info
trace level is generally not useful in sentinel features.
It is important to put effort into designing the tracing a features does so:
-
there is useful information available for troubleshooting
-
unexpected behaviour does not cause a snowballing number of warning and severe trace messages that impact the stability of the platform.
Rule | Rationale | Exceptions |
---|---|---|
Always guard trace statements. if (tracer.isXEnabled()) { ... } |
This pattern avoids unnecessary overhead caused when evaluating the argument to the tracer (eg string concatenation), when the trace message would not be written. |
The pattern should be followed in all cases for consistency, even when there is no overhead required to evaluate the argument of tracer methods. |
Tracer messages written at |
This allows |
Always follow this rule. |
Features should trace |
Allows for simple, consistent search in log files to follow control flow. |
Always follow this rule. |
Features should minimise using |
This avoids the possibility of log spam on production systems, which could compound failures (for example during severe load) |
Generally avoid these trace levels in features. Use statistics instead. |
Features should rarely use |
Logging of feature execution should be done at |
Using |
Java uses eager evaluation - all arguments to a method are evaluated before the method itself is executed. This includes calls to tracers.
Remember that the |
Using Statistics
Statistics associate counters with actions a feature performs, such rejecting a session, or unexpected situations, such as an external system not being available. Platform administrators can use statistics to track stability and performance; for example, noting how long an external component takes to answer a request or how many retries a feature has had to make.
Rule | Rationale | Exceptions |
---|---|---|
Feature statistics should represent problem domain related occurrences that reflect the behaviour of the feature. |
Statistics provide a low impact method to monitor the behaviour of Sentinel. |
Always follow this recommendation |
Don’t replicate feature statistics that are already collected by the Sentinel core. |
The sentinel core already collects statistics when a feature runs, and related to the outcome (failing to start, issued a warning and so on). |
Always follow this recommendation |
Consider defining threshold alarms |
A threshold alarm is a custom alarm that is created by the platform administrator. Threshold alarms are raised or cleared automatically based rules that are based on statistics. |
Using the Feature API
Rule | Rationale | Exceptions |
---|---|---|
One of …
must be called when a feature’s main control block completes. If the feature is waiting for an asynchronous non-sip event, |
The sentinel run-time requires features to signal the outcome of being invoked, so it can update its own state and continue running other features. |
Always follow this rule. For SIP-only features, or features with no asynchronous calls, trace |
|
The Sentinel run-time collects statistics related to feature failures that can be monitored. |
Always follow this rule. |
|
The Sentinel run-time collects statistics that can be monitored by the platform operator |
The decision about whether to call |
|
The Sentinel run-time collects statistics that can be monitored by the platform operator |
In general, if the problem is internal to the system - eg a timer cannot be set - |
Dependencies and Annotations
Rule | Rationale | Exceptions | ||
---|---|---|---|---|
Don’t hard-code name/vendor/version values. |
If the version of a dependency changes, you have to change it in all places it is used. |
Always follow this rule. |
||
Add dependencies to the slee-component ivy conf |
The sentinel build system inspects resolved dependencies at build time and, where possible, sets variables that can be used during annotation processing.
|
Always follow this rule. |
||
For example … Ivy dependency
<dependency org="${sdk.ivy.org}" name="volte-example-pojo-feature-library" rev="latest.${ivy.status}" branch="${branch.name}" conf="self, provisioning -> api; api; slee-component; slee-binding"/> Annotation in a feature
@LibraryReferences( libraryRefs = { @LibraryReference( library = @ComponentId(name = "@volte-example-pojo-feature-library.name@", vendor = "@volte-example-pojo-feature-library.vendor@", version = "@volte-example-pojo-feature-library.version@")) } ) Output from the build (ant -v)
... [oc:finddepcomponentinfo] Processing module: volte-example-pojo-feature-library [oc:finddepcomponentinfo] Adding property: name=volte-example-pojo-feature-library.name, value=volte-example-pojo-feature-library [oc:finddepcomponentinfo] Adding property: name=volte-example-pojo-feature-library.vendor, value=OpenCloud [oc:finddepcomponentinfo] Adding property: name=volte-example-pojo-feature-library.version, value=2.7.0-TRUNK ... Generated fragment of the deployment descriptor
... <library-ref> <library-name>volte-example-pojo-feature-library</library-name> <library-vendor>OpenCloud</library-vendor> <library-version>2.7.0-TRUNK</library-version> </library-ref> ... |
||||
Minimise the number of dependencies in |
Ivy is a transitive package manager. Make use of ivy and only include the direct dependencies your components need and let ivy transitively resolve the rest. |
Follow this rule unless you need fine grained control of transitive dependencies, for example to exclude a component. |
Using Cassandra CQL
Rule | Rationale | Exceptions |
---|---|---|
Prepared statements should used in preference to executing raw strings when using the cassandraCQLProvider |
Efficiency and security |
There may be some situations where prepared statements are not practical or efficient, and in those cases raw strings can be used |
Using SLEE Profiles
Rule | Rationale | Exceptions |
---|---|---|
Each profile specification should include a profile management class that extends |
|
Always follow this rule. |
See Chapter 10 Profiles and Profile Specifications of the SLEE specification.
|
Using SIP
Rule | Rationale | Exceptions |
---|---|---|
Prefer using sip header names from predefined classes, eg |
Avoids typos and regional spelling differences |
Whenever importing the relevant libraries is not feasible |
Feature Configuration
Rule | Rationale | Exceptions |
---|---|---|
Feature configuration should be provisioned using the @Provisioning annotation. |
These annotations are used to generate the REST API and web UI for the feature. |
If configuration profiles are shared between multiple features, only one feature should be responsible for provisioning. |
Session State
Rule | Rationale | Exceptions |
---|---|---|
the |
Proper initialisation of session state fields means that less validation logic is needed, spread throughout the features that use the session state fields. |
Use this pattern whenever:
|
Using the SIP Leg Manager
Rule | Rationale | Exceptions |
---|---|---|
Don’t look up legs by name - use the ACI instead |
|