Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 0 additions & 5 deletions modules/eventing/pages/eventing-Terminologies.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -108,8 +108,3 @@ Newly created handlers start in an undeployed state.
When a Function gets deleted, the source code implementing the Function, all processing checkpoints, and other artifacts in the metadata provider are purged.
Before deleting, make sure you have undeployed the Function.

== Timers

Timers provide execution of code at a preconfigured clock time or after a specified number of seconds.
Using timers, you can write a simple JavaScript Function handler code to delay or trigger the execution of a Function at specific wall-clock time events.
Timers allow archiving of expired documents at a preconfigured clock time.
2 changes: 1 addition & 1 deletion modules/eventing/pages/eventing-adding-function.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ Additional controls are now displayed: The controls are:
. Click *Deploy*.
This displays the *Confirm Deploy Function* dialog.
The Feed Boundary determines whether documents previously in existence needs to be included in the Function's activities: the options are *Everything* and *From now*.
The *Everything* option invokes a Function on all the data present in the cluster.
The *Everything* option invokes a Function on all mutations available in the cluster.
The *From now* option invokes a Function during future instances of data mutation, post Function deployment.
. Click *Deploy* Function.
This deploys the Function and returns you to the main Eventing screen.
Expand Down
2 changes: 2 additions & 0 deletions modules/eventing/pages/eventing-api.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
[abstract]
The Functions REST API, available by default at port 8096, provides the methods available to work with Couchbase Functions.

NOTE: The Functions REST API is a Beta feature intended for development purposes only, do not use them in production; no Enterprise Support is provided for Beta features.

.Functions API
[cols="2,3,6"]
|===
Expand Down
120 changes: 0 additions & 120 deletions modules/eventing/pages/eventing-examples.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -353,123 +353,3 @@ image::query-results-ondelete.png[,400]

. In the *Query Results* pane notice that user_ids, *user_id4* and *user_id 10* are removed as part of the cascade user delete operation.

== Example 4

*Goal*: When a document in an existing bucket is about to expire, a new document is created in a newly created bucket.

*Implementation*: Write an OnUpdate handler, which runs whenever a document is created or mutated.
The handler calls a timer routine, which executes a callback function, two minutes prior to any document’s established expiration.
This function retrieves a specified value from the document, and stores it in a document of the same name, in a specified target bucket.
The original document in the source bucket is not changed..

For this example, the buckets created such as source, target, and metadata buckets, are used.
A new document is created within the source bucket, and this document has its expiration — or Time To Live (TTL) — set to occur ten minutes after the document's creation.

Python script for this Example is provided for reference.
Using the Couchbase SDK, you can create or modify the document expiration.
In this example, the Couchbase SDK Python client creates a document and sets the document's expiration.

----
from couchbase.cluster import Cluster
from couchbase.cluster import PasswordAuthenticator
import time
cluster = Cluster('couchbase://localhost:8091')
authenticator = PasswordAuthenticator('Administrator', 'password')
cluster.authenticate(authenticator)

cb = cluster.open_bucket('source')
cb.upsert('SampleDocument2', {'a_key': 'a_value'})
cb.touch('SampleDocument2', ttl=10*60)
----

The script imports a Couchbase cluster object, and authenticates against it, using (for demonstration purposes) the Full Administrator username and password (the cluster is assumed to be accessible on localhost).
The script then opens the existing source bucket, and inserts a new document, named *SampleDocument2*, whose body is *{'a_key': 'a_value'}*.

For information on installing the Couchbase Python SDK, refer to xref:java-sdk::start-using-sdk.adoc[Start Using the SDK].
For information on using the Couchbase Python SDK to establish bucket-expiration, refer to xref:dotnet-sdk::document-operations.adoc[Document Operations].

*Procedure*

Proceed as follows:

. Install the Couchbase SDK Python client and from the appropriate folder, start Python.
+
----
./python
----

. On the Python prompt, enter the provided code.
+
----
>>> from couchbase.cluster import Cluster
>>> from couchbase.cluster import PasswordAuthenticator
>>> import time
>>> cluster = Cluster('couchbase://localhost:8091')
>>> authenticator = PasswordAuthenticator('Administrator', 'password')
>>> cluster.authenticate(authenticator)
>>> cb = cluster.open_bucket('source')
>>> cb.upsert('SampleDocument2', {'a_key': 'a_value'})
OperationResult<rc=0x0, key='SampleDocument2', cas=0x1519ec8cdee90000>
>>> cb.touch('SampleDocument2', ttl=10*60)
OperationResult<rc=0x0, key='SampleDocument2', cas=0x1519ec8e686c0000>
>>>
----

. To verify bucket creation, access the *Buckets* screen from the *Couchbase Web Console* and click the *Document* tab of the *Source* bucket.
The new document gets displayed.
. [Optional Step] Click on a document's id to view the metadata information.
. From the *Couchbase Web Console* > *Eventing* page, click *ADD FUNCTION*, to add a new Function.
The *ADD FUNCTION* dialog appears.
. In the *ADD FUNCTION* dialog, for individual Function elements provide the below information:
** For the *Source Bucket* drop-down, select *source*.
** For the *Metadata Bucket* drop-down, select *metadata*.
** Enter *add_timer_before_expiry* as the name of the Function you are creating in the *FunctionName* text-box.
** Enter text *Function that adds timer before document expiry*, in the *Description* text-box.
** For the *Settings* option, use the default values.
** For the *Bindings* option, add two bindings.
For the first binding specify *source* as the name of the bucket, and specify *src* as the associated value.
For the second binding, specify *target* as the name of the bucket, and specify *tgt* as the associated value.
. After providing all the required information in the *ADD FUNCTION* dialog, click *Next: Add Code*.
The *add_timer_before_expiry* dialog appears.
. The *add_timer_before_expiry* dialog initially contains a placeholder code block.
You will substitute your actual *add_timer_before_expiry code* in this block.
+
image::casacade_del_withcode.png[,600]

. Copy the following Function, and paste it in the placeholder code block of *add_timer_before_expiry* dialog.
+
----
function OnUpdate(doc, meta) {
if (meta.expiration > 0 ) //do only for those documents that have a non-zero TTL
{
var expiry = new Date(meta.expiration);
// Compute 2 minutes from the TTL timestamp
var twoMinsPrior = new Date(expiry.setMinutes(expiry.getMinutes()-2));
var context = {docID : meta.id};
createTimer(DocTimerCallback, twoMinsPrior , meta.id, context);
log('Added Doc Timer to DocId:', meta.id);
}
}
function DocTimerCallback(context)
{
log('DocTimerCallback Executed for DocId:', String(context.docID));
tgt[context.docID] = "To Be Expired Key's Value is:" + JSON.stringify(src[context.docID]);
log('Doc Timer Executed for DocId', String(context.docID));
}
----
+
After pasting, the screen appears as displayed below:
+
image::casacade_del_withcode.png[,600]

. Click *Save*.
. To return to the Eventing screen, click *Eventing* tab.
. From the *Eventing* screen, click *Deploy*.
. In the *Confirm Deploy Function* dialog, select *Everything from the Feed boundary* option.
. Click *Deploy*.
The function is deployed and starts running within a few seconds.
+
image::cascade_delete_buckets.png[,600]
+
As a result, a new document — like the original, named *SourceDocument2* — is created, with a value based on that of the original.
After two minutes has elapsed, check the documents within the source bucket: the original *SourceDocument2* is no longer visible, having been removed at its defined expiration-time.
20 changes: 0 additions & 20 deletions modules/eventing/pages/eventing-faq.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -142,23 +142,3 @@ All changes from a document are always processed in order.
+
We block one of the mutations alone and hand it over to the debugger session.
The rest of the mutations continue to be serviced by the event handler.

* Are timers scalable?
+
Timers get automatically sharded across Eventing nodes and therefore are elastically scalable.
Due to sharding, 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 time was created, or on a different node.
Relative ordering between two specific timers cannot be maintained.

* Can I use Debugger to debug timers?
+
Timers cannot be debugged using the Visual Debugger.

* What happens when the Function handler code contains a timestamp in the past?
+
When a Function handler code contains a timestamp in the past, upon a successful Function deployment, the system executes the code in the next available time slot.

* What is the Timer behavior post reboot?
+
During a boot operation, all clocks in the cluster nodes get synchronized.
Post-startup, cluster nodes get periodically synchronized using clock synchronization tools such as Network Time Protocol (NTP).
186 changes: 85 additions & 101 deletions modules/eventing/pages/eventing-language-constructs.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,8 @@ Operations that return values are accessible through a special iterator on which
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.

IMPORTANT: The N1QL construct is still in development and may have some rough edges and bugs, and may change significantly before the final GA release.
This release version of Couchbase Server 5.5 is intended for development purposes only.
IMPORTANT: The N1QL queries in events are a BETA feature and may have some rough edges and bugs, and may change significantly before the final GA release.
This pre-release version of the feature is intended for development purposes only; no Enterprise Support is provided for Beta features.

The iterator is an input iterator (elements are read-only).
The keyword _this_ cannot be used in the body of the iterator.
Expand All @@ -113,6 +113,89 @@ function OnUpdate(doc, meta) {
break; // Cancel streaming query by breaking out.
}
}

----
The Function handler code supports N1QL queries.
Top level N1QL keywords, such as SELECT, UPDATE, and INSERT, are available as keywords in Functions.

During deployment, if a handler code includes an N1QL query, then the system generates a warning message.
[.out]``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 [.var]`$<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 [.param]`meta.id` expression in the query statement.

Instead of [.param]`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, 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 [.param]`beer-sample`, then use the N1QL query such as:
+
----
SELECT * FROM `beer-sample` WHERE type...
----

* If bucket name is [.param]`beersample`, then use the N1QL query such as:
+
----
SELECT * FROM beersample WHERE type ...
----
The Function handler code supports N1QL queries.
Top level N1QL keywords, such as SELECT, UPDATE, and INSERT, are available as keywords in Functions.

During deployment, if a handler code includes an N1QL query, then the system generates a warning message.
[.out]``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 [.var]`$<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 [.param]`meta.id` expression in the query statement.

Instead of [.param]`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, 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 [.param]`beer-sample`, then use the N1QL query such as:
+
----
SELECT * FROM `beer-sample` WHERE type...
----

* If bucket name is [.param]`beersample`, then use the N1QL query such as:
+
----
SELECT * FROM beersample WHERE type ...
----

[#handler-signatures]
Expand Down Expand Up @@ -237,102 +320,3 @@ During the Function deployment step, when the system validates the handler code,
Reserved words as a property bindings value

image::reserved-words.png[,300]

== *Support for N1QL in Function Handlers*

IMPORTANT: The N1QL queries in events are a BETA feature and may have some rough edges and bugs, and may change significantly before the final GA release.
This Beta-release version of Couchbase Server 5.5 is intended for development purposes only; no Enterprise Support is provided for Beta features.

The Function handler code supports N1QL queries.
Top level N1QL keywords, such as SELECT, UPDATE, and INSERT, are available as keywords in Functions.

During deployment, if a handler code includes an N1QL query, then the system generates a warning message.
[.out]``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 [.var]`$<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 [.param]`meta.id` expression in the query statement.

Instead of [.param]`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, 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 [.param]`beer-sample`, then use the N1QL query such as:
+
----
SELECT * FROM `beer-sample` WHERE type...
----

* If bucket name is [.param]`beersample`, then use the N1QL query such as:
+
----
SELECT * FROM beersample WHERE type ...
----

== Timers

*Creating a Timer*

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.

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.

A few ascpects related to timer construct are listed below:

* Bindings can be reused in timers.
Bindings, created during the Function definition, can be accessed by the timer constructs in the Function handler code.
* When logging is enabled, timer related logs get captured as part of the Application logs.
* Timers get deleted when the associated Function is deleted or undeployed.
* While using timers, ensure that other applications do not use the metadata bucket.
The metadata bucket stores information about timers and its association with a Function.
Therefore, the metadata bucket should not be deleted or flushed, or the keys be 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 triggering of timer gets permanently blocked.
* For easy debugging, Couchbase recommends enclosing of timers in a try-catch block.
* 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.
Loading