Supported Operations in a Function Handler Code

Following operations are supported inside a Function handler code:

Bucket Operations

Using the bucket accessors construct, you can read documents from a specific bucket and also perform write operations to other buckets.

Language Construct for Bucket Accessors

Bucket accessors provide access to an object’s properties by using the dot notation. Bucket accessors is one among the three added language constructs.

Couchbase Buckets that are associated with a Function appears as a global JavaScript map. All map operations such as get, set, and delete are mapped to their respective get, set and delete operations in the Data Service provider.

function OnUpdate(doc, meta) {
  // Assuming 'dest' is a bucket alias binding
  var val = dest[meta.id];         // this is a bucket GET operation.
  dest[meta.id] = {"status":3};    // this is a bucket SET operation.
  delete dest[meta.id];            // this is a bucket DEL operation.
}

For a sample Bucket Operation, see Try Bucket Operation.

N1QL Queries

Top level N1QL keywords, such as SELECT, UPDATE, and INSERT, are available as keywords in Functions.

Support for N1QL queries is still in development and may have some rough edges and bugs, and may change significantly before the final GA release. This version is intended for development purposes only, do not use them in production; no Enterprise Support is provided for Developer Preview features.

Language Construct for N1QL Queries

N1QL query is the second among the three added language constructs.

Operations that return values are accessible through a special iterator on which the for (var <row> of <iterator>) looping-construct has been defined. This restricted looping-construct allows support of query-result streaming, and automatic query-cancellation when the iterator goes out of scope.

Any variable that is reachable from the scope of the N1QL query can be referred to using $<variable> syntax in the N1QL statement, where parameters get substituted according to the rules of the named-parameter substitution in the N1QL grammar specification.

The iterator is an input iterator (elements are read-only). Keywords cannot be used in the body of the iterator. The variables created inside the iterator are local to the iterator.

function OnUpdate(doc, meta) {
  var strong = 70;
  var stmt =
    SELECT *                  // N1QL queries are embedded directly.
    FROM `beer-samples`       // Token escaping is standard N1QL style.
    WHERE abv > $strong;      // Local variable reference using $ syntax.
  for (var beer of stmt) {  // Stream results using 'for' iterator.
    break;                   // Cancel streaming query by breaking out.
  }
}

For a sample N1QL Operation, see Try N1QL Operation.

During deployment, if a handler code includes an N1QL query, then the system generates a warning message.

Warning Message: "Handler <function_name> uses Beta features. Do not use in production environments."

However, the warning message does not prevent the Function deployment.

You must use $<variable>, as per N1QL specification, to use a JavaScript variable in the query statement. The object expressions for substitution are not supported and therefore you cannot use the meta.id expression in the query statement.

Instead of meta.id expression, you can use var id = meta.id in an N1QL query.

Invalid N1QL query

DELETE FROM `transactions` WHERE username = $meta.id;

Valid N1QL query

var id = meta.id;
DELETE FROM `transactions` WHERE username = $id;

When you use a N1QL query inside a Function handler code, remember to use an escaped identifier for bucket names with special characters ([.var]`bucket-name`). Escaped identifiers are surrounded by backticks and support all identifiers in JSON.

For example:

If the bucket name is beer-sample, then use the N1QL query such as:

SELECT * FROM `beer-sample` WHERE type…

If bucket name is beersample, then use the N1QL query such as:

SELECT * FROM beersample WHERE type ...

The example section provides an example for using N1QL queries, refer to Cascade Delete.

Reserved Keywords

Reserved words are words that cannot be used as a variable name, function name, or as a property in the Function handler code. The following table lists the reserved words that you must refrain from using as they are used by Couchbase’s query language, N1QL.

N1QL Keywords

ALTER

EXECUTE

MERGE

UPDATE

BUILD

EXPLAIN

PREPARE

UPSERT

CREATE

GRANT

RENAME

DELETE

INFER

REVOKE

DROP

INSERT

SELECT

What Happens If You Use a Reserved Word?

Let’s say you try to create a new Function handler code using a reserved word for variable names, for function names, and as a property bindings value. All three cases generate a deployment error.

Reserved words as a variable name:

function get_numip_first_3_octets(ip)
{
  var grant = 0;
  if (ip)
  {
	var parts = ip.split('.');
  }
}

Reserved words as a function name:

function grant(ip)
{
  var return_val = 0;
  if (ip)
  {
    var parts = ip.split('.');
  }
}

During the Function deployment step, when the system validates the handler code, it displays an error message

Sample Error Message - Deployment failed: Syntax error (<line and column numbers>) - grant is a reserved name in N1QLJs

An sample Reserved words as a property bindings value is displayed below:

reserved words

Timers

Timers are asynchronous compute which offers Function execution in reference to wall-clock events. Timers also measure and track the amount of elapsed time and can be used while archiving of expired documents at a preconfigured time.

Few important aspects related to timers are listed below:

  • Timers follow the same timeout semantics as their Parent Functions. So, if a Function has an execution timeout of 60 seconds, each of the timers created from the Function inherits the same execution timeout value of 60 seconds.

  • Timers may run on a different node than the one on which it was created.

  • One execution of timers is guaranteed despite node failures and cluster rebalances.

  • During Function backlogs, timers get eventually executed.

  • The metadata bucket stores information about timers and its association with a Function.

  • Ensure that the metadata bucket is not deleted or flushed, or the keys in metadata bucket get updated.

  • With an increase in the usage of timers, the metadata memory assignment must also be increased. Due to runtime or programmatic errors in the function handler code, if triggering of a timer fails, then timer execution may get permanently blocked.

  • Bindings can be reused in timers. Bindings, created during the Function definition, can be accessed by the timer constructs in the Function handler code.

  • Timers get deleted when the associated Function is deleted or undeployed.

Language Constructs for Timers

Timers is the third added language constructs.

To create a timer use the below syntax:

   createTimer(callback, timestamp, reference, context)

In the createTimer syntax:

  • callback - is the function called when the timer gets triggered. You need to ensure that the callback function is the top-level function that takes a single argument, the context.

  • timestamp - is the JavaScript Date object timestamp at which the Function handler code must be executed.

  • reference - is a unique string that gets passed. This string helps to identify the timer that is being created. All callback and references are scoped to the Function definition. Also, all references must be unique within the Function scope. When multiple timers are created with the same unique reference, old timers (with the same unique reference) get canceled.

  • context - is any JavaScript object that can be serialized. When the timer gets triggered, the context specified during timer creation gets passed to the callback Function. For optimal performance, the context object payload needs to be lesser than 100 KB.

Sample Timer Construct

A sample createTimer language construct is provided for reference.

   createTimer(DocTimerCallback, twoMinsPrior, meta.id, context)

In the sample construct:

  • DocTimerCallback is the name of the function used in the Function handler code.

  • twoMinsPrior is a JavaScript Date object.

  • meta.id is a generic reference string that can be used in the Couchbase cluster.

  • context is the JavaScript object that is used in the Function handler code.

Sharding of Timers

Timers get automatically sharded across Eventing nodes and therefore are elastically scalable. Triggering of timers at or after a specified time interval is guaranteed. However, triggering of timers may either be on the same node (where the timer was created), or on a different node. Relative ordering between two specific timers cannot be maintained.

Debugging and Logs

Timers cannot be debugged using the Visual Debugger tool. For debugging, Couchbase recommends enclosing of timers in a try-catch block. When logging is enabled, timer related logs get captured as part of the Application logs.

Elapsed Timestamps

During runtime, when a Function handler code contains a timestamp in the past (elapsed timestamp), the system executes the code in the next available time window, as soon as all the required resources are available.

Handling Delays

During Function backlogs, execution of timers may be delayed. To handle these delays, you need to program additional time window in your code. If your business logic is time-sensitive after this additional time window the code should refrain from its Function execution.

The following is a sample code snippet which performs a timestamp check (my_deadline) before code execution.

func callback(context)
{
  //context.my_deadline is the parameter in the timer payload
    if new Date().getTime() > context.my_deadline
      {
        // timestamp is back-dated, do not execute the rest of the timer
        return;
       }
}

The Eventing Example section provides an example for Timers, Document Expiry and Archival

REST APIs and cURL Operations

curl is a generic, language agnostic way to facilitate HTTP requests and responses.

Inside Function handler code, using REST APIs, you can execute a cURL function to make requests to HTTP endpoints. Endpoints are resources on a web server at a specific path.

REST APIs are supported in a non-production environments.

If you prefer to work with APIs to invoke a REST endpoints, then use the below link to help you get started.