The GOTO processor enables dynamic execution of other transmissions within the Transmissions framework, providing powerful flow control and subroutine functionality.
GOTO allows a transmission to dynamically call and execute another transmission, passing the current message through the target transmission's pipeline. This enables patterns like:
transmissions.ttl:
@prefix : <http://purl.org/stuff/transmissions/> .
:main-workflow a :EntryTransmission ;
:pipe (:start :conditional-goto :end) .
:start a :NOP .
:conditional-goto a :GOTO ;
:settings :targetConfig .
:end a :ShowMessage .
# Target transmissions (subroutines)
:process-a a :Transmission ;
:pipe (:step1 :step2) .
:process-b a :Transmission ;
:pipe (:stepX :stepY) .
:step1 a :NOP .
:step2 a :ShowMessage .
:stepX a :NOP .
:stepY a :ShowMessage .
config.ttl:
@prefix : <http://purl.org/stuff/transmissions/> .
:targetConfig a :ConfigSet ;
:gotoTarget "process-a" .
main-workflow
starts (marked as :EntryTransmission
)start
processor executesconditional-goto
(GOTO) processor:"process-a"
process-a
process-a
with current messageend
processor executes with result from process-a
The GOTO target can be specified in multiple ways, following standard getProperty()
priority:
// Runtime target selection
message.gotoTarget = "process-b" // Overrides config
:targetConfig a :ConfigSet ;
:gotoTarget "process-a" .
// In GOTO processor
const target = super.getProperty(ns.trn.gotoTarget, "default-process")
GOTO targets can be specified as:
:gotoTarget "process-name" .
http://purl.org/stuff/transmissions/process-name
:gotoTarget <http://purl.org/stuff/transmissions/process-name> .
:gotoTarget :process-name .
:EntryTransmission
)Entry transmissions are automatically executed when the application starts:
:main-app a :EntryTransmission ; # Auto-executed
:pipe (:processor1 :goto-step :processor2) .
:Transmission
)Target transmissions are available for GOTO calls but don't auto-execute:
:subroutine a :Transmission ; # Available for GOTO, no auto-execution
:pipe (:sub-step1 :sub-step2) .
If no :EntryTransmission
types are found, the system falls back to original behavior (runs all transmissions). This ensures existing applications continue working without modification.
Use message properties to determine target at runtime:
Processor setting target:
// In a custom processor
if (condition) {
message.gotoTarget = "success-path"
} else {
message.gotoTarget = "error-path"
}
GOTO processor:
:router a :GOTO ;
:settings :dynamicTarget .
Create reusable processing modules:
# Main workflow
:data-processor a :EntryTransmission ;
:pipe (:validate :process :finalize) .
:validate a :GOTO ;
:settings :validationTarget .
:process a :GOTO ;
:settings :processingTarget .
:finalize a :ShowMessage .
# Reusable subroutines
:validate-user-data a :Transmission ;
:pipe (:check-schema :check-permissions) .
:validate-file-data a :Transmission ;
:pipe (:check-format :check-size) .
:process-batch a :Transmission ;
:pipe (:split-batch :process-items :aggregate) .
:process-single a :Transmission ;
:pipe (:transform :validate-output) .
Dynamic configuration:
// Route based on data type
if (message.dataType === "user") {
message.gotoTarget = "validate-user-data"
} else if (message.dataType === "file") {
message.gotoTarget = "validate-file-data"
}
GOTO provides graceful error handling:
// In GOTO processor
try {
const result = await targetTransmission.process(message)
return this.emit('message', result)
} catch (error) {
logger.error(`GOTO: Error executing '${targetId}': ${error.message}`)
// Continue with original message on error
return this.emit('message', message)
}
Target transmissions can contain their own GOTO processors:
:main a :EntryTransmission ;
:pipe (:start :goto1) .
:level1 a :Transmission ;
:pipe (:process1 :goto2) .
:level2 a :Transmission ;
:pipe (:process2 :final) .
This creates a call stack: main
→ level1
→ level2
The GOTO processor uses ProcessorImpl.findTransmission()
to locate targets:
findTransmission(targetId) {
// Convert short name to full URI if needed
let fullUri = targetId
if (!targetId.startsWith('http://')) {
fullUri = `http://purl.org/stuff/transmissions/${targetId}`
}
// Search app.transmissions array
for (const transmission of this.app.transmissions) {
if (transmission.id === fullUri) {
return transmission
}
}
return null
}
getProperty(ns.trn.gotoTarget)
All transmissions are stored in app.transmissions
array, making them accessible to GOTO processors regardless of whether they're entry points or targets.
GOTO: Target transmission 'nonexistent' not found, continuing with current message
The processor logs a warning and continues with the original message.
GOTO: Error executing target transmission 'faulty-target': ReferenceError: undefined variable
The processor logs the error and continues with the original message.
GOTO: No target transmission specified, continuing with current message
If no gotoTarget
property is found, the processor passes the message through unchanged.
Example test execution:
./trans goto
Expected output:
+ Run Transmission : goto-test
|-> p10 a GOTO
+ Run Transmission : goto-target1
|-> p100 a ShowMessage
[target execution output]
|-> p20 a ShowMessage
[main pipeline continuation]
Use descriptive names for target transmissions:
validate-user-input
process-payment
target1
proc
Include comments showing GOTO relationships:
# Main workflow - calls validation and processing subroutines
:user-registration a :EntryTransmission ;
:pipe (:collect-data :validate-goto :process-goto :confirm) .
# Called by validate-goto
:validate-user-data a :Transmission ;
:pipe (:check-email :check-password :check-terms) .
# Called by process-goto
:process-registration a :Transmission ;
:pipe (:create-account :send-email :update-metrics) .
Design target transmissions to handle their own errors gracefully rather than relying on GOTO's error handling.
Limit GOTO call depth to maintain readability and debugging ease. Consider refactoring deeply nested calls into sequential processing.
Target transmissions should be testable independently:
# Test individual target
./trans goto.validate-user-data
# Test main workflow
./trans goto
Feature | GOTO | Nested Transmissions | Fork/Choice |
---|---|---|---|
Dynamic Targets | ✅ Runtime selection | ❌ Static definition | ❌ Static branches |
Reusability | ✅ Shared subroutines | ❌ Embedded only | ❌ Local branches |
Complexity | Medium | Low | Low |
Performance | Medium | High | High |
Use Case | Conditional routing, subroutines | Hierarchical composition | Parallel processing |
The GOTO processor provides unique capabilities for dynamic flow control that complement the existing nested transmission and flow control features of the Transmissions framework.