go.temporal.io/server/chasm/registrable_component.go
233 LOC · 91 covered · 142 uncovered · 38 ranges · 22043 concepts · 24 introducers · 10883 tests
File neighbourhood
The centred file is linked to every concept that introduces one of its ranges, every test that runs code from the file, and the gray connector concepts standing between those tests and the file's own introducer concepts. Undirected links join concepts to every file where they introduce source and concepts to the tests they introduce; arrows show specialization between the displayed concepts and bridge only concepts omitted from this view. Concept colors match the source ranges below; connector concepts have no source color and are shown in gray.
Focused file, its introducer and connector concepts, their introduced files, and tests that run code from the file
In the embedded map, ordinary wheel input scrolls the page; use the visible controls to zoom and drag to pan. Open the full-screen map for canvas navigation: wheel pans, Ctrl/Command plus wheel zooms, and arrow keys pan when this region is focused. On touch screens, open the full-screen map to pan or pinch. If JavaScript or WebGL is unavailable, use the related-file, concept, and source links on this page.
Graph controls are ready.
Interactive rendering requires JavaScript and WebGL. Use the related-file, concept, and source links on this page while the interactive map is unavailable.
package chasm
import (
"fmt"
"maps"
"reflect"
"github.com/dgryski/go-farm"
enumspb "go.temporal.io/api/enums/v1"
"go.temporal.io/server/common/searchattribute/sadefs"
)
type (
RegistrableComponent struct {
componentType string
goType reflect.Type
// Following three fields are initialized when the component is registered to a library.
library namer
componentID uint32
fqn string
ephemeral bool
singleCluster bool
detached bool
searchAttributesMapper *VisibilitySearchAttributesMapper
contextValues map[any]any
}
RegistrableComponentOption func(*RegistrableComponent)
)
func NewRegistrableComponent[C Component](
componentType string,
opts ...RegistrableComponentOption,
rc := &RegistrableComponent{
componentType: componentType,
goType: reflect.TypeFor[C](),
}
for _, opt := range opts {
}
}
func WithEphemeral() RegistrableComponentOption {
return func(rc *RegistrableComponent) {
rc.ephemeral = true
}
}
// Is there any use case where we don't want to replicate certain instances of a archetype?
func WithSingleCluster() RegistrableComponentOption {
return func(rc *RegistrableComponent) {
rc.singleCluster = true
}
}
// WithDetached marks the registrable component as detached. Detached components ignore
// parent lifecycle validation, allowing them to continue operating when their
// parent is closed/terminated.
// If a registrable component is not detached by default, a component definition
// can specify its child as detached via ComponentFieldDetached() option.
return func(rc *RegistrableComponent) {
rc.detached = true
}
}
// IsDetached returns true if the component type is registered as detached.
return rc.detached
}
// WithBusinessIDAlias allows specifying the business ID alias of the component.
// This option must be specified if the archetype uses the Visibility component.
func WithBusinessIDAlias(
alias string,
return func(rc *RegistrableComponent) {
if rc.searchAttributesMapper == nil {
}
//nolint:forbidigo
panic(fmt.Sprintf("registrable component validation error: business ID alias %q is already defined as a search attribute", alias))
}
if _, ok := rc.searchAttributesMapper.systemAliasToField[alias]; ok {
registrable_component.go ×5
//nolint:forbidigo
panic(fmt.Sprintf("registrable component validation error: business ID alias %q is already defined as a system search attribute", alias))
}
rc.searchAttributesMapper.systemAliasToField[alias] = sadefs.WorkflowID
registrable_component.go ×5
rc.searchAttributesMapper.fieldToAlias[sadefs.WorkflowID] = alias
rc.searchAttributesMapper.saTypeMap[sadefs.WorkflowID] = enumspb.INDEXED_VALUE_TYPE_KEYWORD
}
}
func WithSearchAttributes(
searchAttributes ...SearchAttribute,
return func(rc *RegistrableComponent) {
if len(searchAttributes) == 0 {
return
}
}
alias := sa.definition().alias
field := sa.definition().field
valueType := sa.definition().valueType
// An identity-mapped system search attribute (alias == field, e.g. TaskQueue,
// ExecutionTime) overrides that system column directly, so it is recorded only in
// overriddenSystemFields; queries resolve via the system column.
if field == alias && sadefs.IsSystem(field) {
//nolint:forbidigo
panic(fmt.Sprintf("registrable component validation error: system search attribute %q cannot be overridden by a CHASM component", field))
}
if _, ok := rc.searchAttributesMapper.overriddenSystemFields[field]; ok {
registrable_component.go ×3
//nolint:forbidigo
panic(fmt.Sprintf("registrable component validation error: system search attribute override %q is already defined", field))
}
rc.searchAttributesMapper.overriddenSystemFields[field] = valueType
registrable_component.go ×3
continue
}
panic(fmt.Sprintf("registrable component validation error: CHASM search attribute alias %q is a CHASM system search attribute", alias))
}
//nolint:forbidigo
panic(fmt.Sprintf("registrable component validation error: CHASM search attribute alias %q is a reserved search attribute", alias))
}
if _, ok := rc.searchAttributesMapper.systemAliasToField[alias]; ok {
registrable_component.go ×5
//nolint:forbidigo
panic(fmt.Sprintf("registrable component validation error: CHASM search attribute alias %q is already defined as a system search attribute alias", alias))
}
panic(fmt.Sprintf("registrable component validation error: search attribute alias %q is already defined", alias))
}
panic(fmt.Sprintf("registrable component validation error: search attribute field %q is already defined", field))
}
rc.searchAttributesMapper.fieldToAlias[field] = alias
rc.searchAttributesMapper.saTypeMap[field] = valueType
}
}
}
// WithContextValues allows specifying key-value pairs that will be available in the Context
// via the Value() method whenever the chasm framework starts, updates, reads, polls, executes or
// validates tasks on a component.
//
// This is useful for propagating values needed for those processing logic but are not avaiable via the
// component's struct definition, such as configurations.
//
// Keys need to be globally unique across components. Conflicting keys across will cause component registration to fail.
//
// Manually added key-value pairs via ContextWithValue() will take precedence over registered context values.
func WithContextValues(
keyVals map[any]any,
return func(rc *RegistrableComponent) {
if rc.contextValues == nil {
rc.contextValues = make(map[any]any, len(keyVals))
}
maps.Copy(rc.contextValues, keyVals)
}
}
func (rc *RegistrableComponent) registerToLibrary(
library namer,
if rc.library != nil {
return "", 0, fmt.Errorf("component %s is already registered in library %s", rc.componentType, rc.library.Name())
registrable_component.go ×1
}
rc.fqn = FullyQualifiedName(rc.library.Name(), rc.componentType)
rc.componentID = GenerateTypeID(rc.fqn)
return rc.fqn, rc.componentID, nil
}
// SearchAttributesMapper returns the search attributes mapper for this component.
func (rc *RegistrableComponent) SearchAttributesMapper() *VisibilitySearchAttributesMapper {
registrable_component.go ×1
return rc.searchAttributesMapper
}
// GenerateTypeID generates a unique 32-bit identifier from a fully qualified name (FQN).
// The generated ID is used to uniquely identify components and tasks within the CHASM framework. The same FQN will
// always produce the same ID.
return farm.Fingerprint32([]byte(fqn))
}
// hasBusinessIDAlias returns true if the component has a businessID alias configured
// via WithBusinessIDAlias option.
if rc.searchAttributesMapper == nil {
}
_, ok := rc.searchAttributesMapper.fieldToAlias[sadefs.WorkflowID]
registrable_component.go ×5
return ok
}
// GoType returns the reflect.Type of the component's Go struct.
return rc.goType
}
// fqType returns the fully qualified name of the component, which is a combination of
// the library name and the component type. This is used to uniquely identify
// the component in the registry.
if rc.fqn == "" {
// this should never happen because the component is only accessible from the library.
panic("component is not registered to a library")
}
}