Overview


The parent of a pico is responsible for initiating the creation and deletion of a pico. The KRL programmer initiates these processes by having the parent receive certain child creation or child deletion events. The KRL programmer can then interact with these processes (such as executing code when they have finished) by selecting on events that occur within the child and parent during the process.

Creating a Pico


A pico can be created by having the parent pico receive a wrangler:child_creation or wrangler:new_child_creation event. Wrangler will pass any attributes added to this event through the event chain.

raise wrangler event "child_creation" attributes {
  "name":"my_new_child", // The name of our new child
  "co_id":meta:rid, // An attribute that will be passed through. "Correlation ID". We will use this to identify the child as the one we made.
  "testParams":{"hello":"world"}, // An attribute that will be passed through.
}

Once this event is raised, Wrangler will behind the scenes create a pico and add it to its internal list of children. The wrangler:children() function will now return an array including this child. 

We can then write a rule that selects on the wrangler:child_initialized event to execute KRL code when the child has been created. We can use the attributes passed through the event chain to validate that this was the child we created, before executing our own code. 

rule onNewTestChild {
  select when wrangler child_initialized where event:attr("co_id") == meta:rid // On a child_initialized event where the co_id attribute matches this rid
  pre {
    testParams = event:attrs{"testParams"} // assign the testParams attribute to "testParams"
  }
  if testParams && testParams{"hello"} then // If testParams exists and it has a value for the "hello" key, fire the rule
  noop()
  fired {
    raise example event "this_ruleset_created_new_child_with_test_params" attributes {}
  }
}

Deleting a Pico


A pico can be deleted by having the parent pico receive a wrangler:child_deletion or wrangler:delete_children event. Wrangler will pass any attributes added to this event through the event chain.

raise wrangler event "child_deletion" attributes {
  "name":"my_new_child",
  "co_id":meta:rid,
  "testParams":{"hello":"world"},
}

As soon as wrangler:child_deletion is raised, Wrangler will remove the pico from its internal list of children and add it to the set of children being deleted. wrangler:children() will no longer return this child.

Note that deleting a child also deletes that child's own children using the same process.

We can then write a rule that selects on the wrangler:child_deleted event to execute KRL code when the child has been deleted. We can use the attributes passed through the event chain to validate that this was the child we deleted, before executing our own code.

rule onTestChildDeleted {
  select when wrangler child_deleted where event:attr("co_id") == meta:rid // On a child_deleted event where the co_id attribute matches this rid
  pre {
    testParams = event:attrs{"testParams"} // assign the testParams attribute to "testParams" 
  }
  if testParams && testParams{"hello"} then // If testParams exists and it has a value for the "hello" key, fire the rule
  noop()
  fired {
    raise example event "this_ruleset_deleted_child_with_test_params" attributes {}
  }
}

Managing Code Startup on Pico Creation


As a developer, you might want to run KRL with the creation of a pico for several different reasons. You might be using the pico as an abstraction for a "job" and want it to start the job as soon as it is created. You might want to do initialization within the pico so that it is ready to receive data from other picos or external sources.

One of the main ways to start code on creation of a pico is by executing code on ruleset installation. Wrangler raises the wrangler:ruleset_installed event whenever you install a ruleset on a pico using wrangler (it uses the wrangler:install_rulesets_requested event). One of the attributes that wrangler:child_creation takes is a "rids"/"rid" parameter. When creating a new pico, Wrangler will install the list of rulesets given in this attribute in the new pico as it is created. Wrangler will then raise wrangler:ruleset_installed as normal, which you can select on and run code with.

Important Notes:

Run Code In New Child Example

// Creates a new child with the "example" ruleset installed and passes an attribute named "testParam"
rule newExampleChild {
  select when example new_child
  always {
    raise wrangler event "child_creation" attributes {
      "rids":"example",
      "testParam":"hello"
    }
  }
}

// In the newly created child this rule will run
rule inNewChild {
  select when wrangler ruleset_installed where rids >< meta:rid
  pre {
    paramFromParent = event:attr("testParam").klog("Should be 'hello'")
  }
  always {
    ent:initial_state := {} // Set a desired initial state of entity variables
  }
}

Create Channel On Installation Example

This example is taken from io.picolabs.subscription ruleset. 

rule create_wellKnown_Rx{
  select when wrangler ruleset_installed where rids >< meta:rid
  pre{ channel = wellKnown_Rx() }
  if(channel.isnull() || channel{"type"} != "Tx_Rx") then
    engine:newChannel(meta:picoId, "wellKnown_Rx", "Tx_Rx")
  fired{
    raise Tx_Rx event "wellKnown_Rx_created" attributes event:attrs;
  }
  else{
    raise Tx_Rx event "wellKnown_Rx_not_created" attributes event:attrs; //exists
  }
}

Create well known Rx rule selects on ruleset_installed event where rids matches its own ruleset rid. Checks for a well known channel, and creates it if one does not exist. Then raises an event detailing the creation. This rule guarantees a well known channel exist, which is a dependency of subscriptions.

Managing Code Cleanup on Pico Deletion


When writing KRL for a pico, you do not always have control over who that pico's parent is, and because the parent is responsible for choosing when the pico is deleted, you do not always have full control over when that may happen. Therefore, as a KRL developer, you may want to attach cleanup code to the event of a pico deletion, such as sending data to another pico or to a remote server. 

Wrangler provides responses to the wrangler:ruleset_needs_cleanup_period event and wrangler:cleanup_finished event to manage this process. If you want your ruleset to be guaranteed some time to clean up before a pico is deleted, you can raise wrangler:ruleset_needs_cleanup_period on the ruleset installation.

rule register_for_cleanup {
  select when wrangler ruleset_installed where event:attr("rids") >< meta:rid // On this ruleset being installed
  always {
    raise wrangler event "ruleset_needs_cleanup_period" attributes { // raise the event
      "domain":meta:rid // the event requires a domain, and meta:rid is a natural choice for this
    }
  }
}

Once this event is raised the domain will be added to an internal list. Then when the parent decides to delete the child, Wrangler will raise a wrangler:rulesets_need_to_cleanup event. The KRL programmer reacts to this event to cleanup, then when done cleaning up, raise a wrangler:cleanup_finished event. It is good practice to raise the wrangler:cleanup_finished event when done so the pico can be cleaned up for space quickly. Otherwise Wrangler waits a timeout period and then simply deletes the pico anyway.

rule cleanup_subscriptions {
  select when wrangler rulesets_need_to_cleanup // When it is time to cleanup
  always {
    raise wrangler event "cancel_subscriptions" attributes event:attrs // Begin cleaning up
  }
}

/* . . . */

// This rule checks if we're done cleaning up after doing cleanup operations
rule done_cleaning_up {
  select when wrangler subscription_removed
           or wrangler outbound_subscription_cancelled
           or wrangler inbound_subscription_cancelled
           or wrangler cancel_relationships
		// after wrangler rulesets_need_to_cleanup 
  if wrangler:isMarkedForDeath() && not hasRelationships() then // wrangler:isMarkedForDeath() can be used to check if a pico is in the process of being deleted.
  noop()
  fired {
    raise wrangler event "cleanup_finished" attributes { 		// We raise wrangler:cleanup_finished to inform Wrangler we're done!
      "domain":meta:rid 										// We give the same domain that we used in wrangler:ruleset_needs_cleanup_period
    }
  }
}


Right now ordering of cleanup is not guaranteed, so it is unwise to rely on mechanisms from other rulesets to be functioning during cleanup. For example, Wrangler tries to cancel all subscriptions as soon as wrangler:rulesets_need_to_cleanup is raised, so the programmer cannot rely on subscriptions. This will likely change in future Wrangler iterations.

Understanding the Lifecycle


This is a general overview of how the creation and deletion processes work under the hood, so that the KRL programmer can more fully understand what is going on behind the scenes.

Pico Creation


Pico Deletion

Note that any attributes passed to the initial wrangler:child_deletion event will be passed as attributes to wrangler:rulesets_need_to_cleanup in all descendants, so this functions as a useful way of giving cleanup parameters to children.

Picos API