Change Handlers consume pending changes detected by processImport and decide what to do (submit jobs, create roles, update users, log tickets, etc.). You select a handler by setting the process/provider in the workflow.
Where they run
After processImport, each row in the data table with a pending action (Create/Update/Delete) is passed to the handler.
<process>
<provider>Innovation.Activate.Library\Innovation.Activate.Connectors.UserChangeHandler</provider>
<options>
<maxChanges>0</maxChanges> <!-- 0 = no limit -->
<batchSize>500</batchSize>
<retry>
<timeout>+2days</timeout> <!-- how long to keep retrying -->
<clear>false</clear> <!-- if true, clear error flag after retries -->
</retry>
</options>
<!-- handler-specific config follows -->
</process>
Common events (inside an <events> block)
- create, update, move, delete, enable, disable
- Steps you can use: submit, execute, notify, end, retry, error, set, ticket, publish, unpublish
Use when connector data represents people that should link to AD users and drive identity lifecycle automation.
<process>
<provider>Innovation.Activate.Library\Innovation.Activate.Connectors.UserChangeHandler</provider>
<user>
<link name="User Account">
<scope>=//Roles/System Roles/Users</scope>
<match when="employeeNumber">(employeeNumber=%=//Current/employeeNumber%)</match>
<match when="domainName">(samAccountName=%=//Current/domainName%)</match>
<match>(givenName=%=//Current/firstName%)(sn=%=//Current/lastName%)</match>
</link>
<!-- Optional: raise enable/disable based on an expression -->
<enabled>=/isActive</enabled>
</user>
<links>
<manager>
<scope>=//Roles/System Roles/Users</scope>
<match when="managerDomainName">(samAccountName=%=//Current/managerDomainName%)</match>
</manager>
</links>
<events>
<create>
<submit>
<task>=//Tasks/User/Create User</task>
<arguments>
<user>
<firstName>%=//Current/firstName%</firstName>
<lastName>%=//Current/lastName%</lastName>
<manager>=//Links/manager</manager>
</user>
</arguments>
</submit>
</create>
</events>
</process>
- User — matched AD user (if found)
- Links — collection of additional linked users (e.g., manager)
- RoleLinks — roles resolved by role link handlers
Use when connector data represents a hierarchy you want as Activate Roles (e.g., departments, locations).
<process>
<provider>Innovation.Activate.Library\Innovation.Activate.Connectors.RoleChangeHandler</provider>
<role>
<root>=//Roles/Departments</root>
<key>DepartmentCode</key>
<field>departmentCode</field>
<name>=//Current/department</name>
<!-- Choose one parent strategy: field reference or explicit link -->
<parent>parentCode</parent> <!-- field reference model -->
<parameters>
<departmentCode name="DepartmentCode" type="String">=/departmentCode</departmentCode>
</parameters>
<events>
<missing>
<createRole>
<description>Created by import %=//System/Now%</description>
</createRole>
</missing>
</events>
</role>
</process>
Events raised by handler: create, update, delete (plus createRole step for new roles)
Use when you need event-driven actions (submit jobs, run scripts) without built-in user/role semantics.
<process>
<provider>Innovation.Activate.Library\Innovation.Activate.Connectors.GenericChangeHandler</provider>
<links>
<!-- optional AD lookups you want available during events -->
</links>
<events>
<create>
<submit>
<task>=//Tasks/Custom/Create Thing</task>
<arguments>
<data>
<externalId>=/id</externalId>
</data>
</arguments>
</submit>
</create>
</events>
</process>
Globals: Links (if configured)
Use when change processing logic itself must be scripted (complex business rules, multi-step orchestration).
<process>
<provider>Innovation.Activate.Library\Innovation.Activate.Connectors.ScriptChangeHandler</provider>
<script>=/ChangeProcessor</script>
<options>
<batchSize>200</batchSize>
</options>
</process>
ServiceDeskTicketChangeHandler
Use when connector data represents tickets you want to create/update inside Activate.
<process>
<provider>Innovation.Activate.Library\Innovation.Activate.Connectors.ServiceDeskTicketChangeHandler</provider>
<user>
<!-- optional user link if tickets should be assigned to people -->
</user>
<ticket>
<!-- define how to match to existing tickets -->
<match field="ticketNumber">=/ticketNumber</match>
<match field="JobID">=/jobId</match>
</ticket>
<events>
<create>
<ticket>
<ticketNumber>=/ticketNumber</ticketNumber>
<name>=/name</name>
<state>=if(=/state, "Closed", "Open")</state>
<status>=/status</status>
<user>=//User</user>
<description>=/details</description>
<notes>=/notes</notes>
</ticket>
</create>
</events>
</process>
Globals: User (if user link configured), Ticket (when matched)
Event Steps (Quick Reference)
- submit — Submit a job/task with arguments.
- execute — Run a script (inline reference).
- notify — Send an email/notification (supports when=errors).
- end — Mark successful end of the current event.
- retry — Keep change pending to retry later.
- error — Mark row as error; respects retry policy.
- set — Set parameter values without a script.
- ticket — Create/update an Activate ticket.
- publish / unpublish — Toggle publication state for provisioning objects.
Troubleshooting & Hardening
- Use options/retry/timeout to bound retry loops; alert on exceeded retries.
- Emit meaningful messages in error so operators can triage quickly.
- Add notify with when=errors and include a table of last error rows.
- For bulk anomalies, prefer end + notify + manual intervention over automated retries.