Notatka
Dostęp do tej strony wymaga autoryzacji. Może spróbować zalogować się lub zmienić katalogi.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
Funkcje zdefiniowane przez użytkownika (UDF) w rejestrze poufnym Azure umożliwiają tworzenie niestandardowych funkcji języka JavaScript uruchamianych wewnątrz granicy zaufania rejestru. Ta funkcja jest prosta i łatwa w użyciu, dzięki czemu można rozszerzyć funkcjonalność interfejsu API rejestru bez konieczności tworzenia złożonych aplikacji. Funkcje zdefiniowane przez użytkownika były wcześniej nazywane prostymi funkcjami zdefiniowanymi przez użytkownika.
Za pomocą wbudowanego interfejsu API języka JavaScript można uruchamiać niestandardowy kod w celu wykonywania różnych zadań, takich jak zapytania niestandardowe i obliczenia, kontrole warunkowe, zadania przetwarzania końcowego i nie tylko. Ta funkcja jest odpowiednia w scenariuszach, w których potrzebna jest bezpośrednia integracja z istniejącym interfejsem API rejestru lub uruchamianie uproszczonej logiki niestandardowej w środowisku poufnym.
Aby uzyskać szybki przegląd i pokaz UDF, obejrzyj następujące wideo:
Uwaga / Notatka
Aby pracować z funkcjami zdefiniowanymi przez użytkownika, użyj wersji 2026-02-23 interfejsu API REST lub nowszej.
Wskazówka
Aby uzyskać bardziej zaawansowane scenariusze, takie jak niestandardowe Role-Based Access Control (RBAC) lub integracja z zewnętrznymi poufnymi obciążeniami roboczymi, zobacz punkty końcowe zdefiniowane przez użytkownika w Azure Confidential Ledger.
Przypadki użycia
Poufne funkcje użytkownika usługi rejestru platformy Azure umożliwiają rozszerzenie funkcjonalności rejestru poprzez uruchamianie logiki niestandardowej. Oto niektóre typowe zastosowania funkcji użytkownika:
Niestandardowe obliczenia i zapytania: uruchamiaj autonomiczne funkcje zdefiniowane przez użytkownika, aby odczytywać lub zapisywać dane w dowolnej tabeli aplikacji rejestru zgodnie z logiką biznesową.
Walidacja danych i kontrola danych wejściowych: używaj funkcji UDF jako kroków wstępnych, aby uruchamiać procesy wstępnego przetwarzania przed zapisaniem wpisu do rejestru, na przykład aby oczyścić dane wejściowe lub sprawdzić warunki wstępne.
Wzbogacanie danych i kontrakty inteligentne: użyj funkcji UDF jako wywołań następczych, aby uruchamiać akcje po zapisaniu wpisu w rejestrze, na przykład w celu dodania niestandardowych metadanych do rejestru lub wyzwalania przepływów pracy po zapisie.
Pisanie funkcji zdefiniowanych przez użytkownika (UDFs)
Poufna funkcja UDF rejestru Azure jest jednostką przechowywaną w rejestrze z unikatowym identyfikatorem i zawiera kod JavaScript, który jest wykonywany, gdy funkcja ta zostaje wywołana. W tej sekcji opisano sposób pisania kodu UDF i używania interfejsu API języka JavaScript do wykonywania różnych zadań.
Struktura funkcji
Kod funkcji zdefiniowanej przez użytkownika wymaga wyeksportowanej funkcji, która jest punktem wejścia skryptu w czasie wykonywania. Podstawowy szablon kodu UDF wygląda następująco:
export function main() {
// Your JavaScript code here
}
Uwaga / Notatka
Nazwa wyeksportowanej funkcji punktu wejścia, która jest wywoływana podczas wykonywania, może zostać zmodyfikowana za pomocą argumentu exportedFunctionName podczas uruchamiania UDF. Jeśli nie zostanie określona, domyślna nazwa to main.
Uwaga / Notatka
Obsługiwane są funkcje lambda, ale wymagają jawnego zdefiniowania wyeksportowanych nazw funkcji i dopasowania jej do nazwy funkcji punktu wejścia. Przykład:
export const main = () => {
// Your JavaScript code here
};
Argumenty funkcji
Możesz określić dowolne opcjonalne argumenty środowiska uruchomieniowego zaakceptowane przez funkcję zdefiniowanej przez użytkownika. Wartości argumentów można przekazać podczas uruchamiania funkcji zdefiniowanej przez użytkownika w czasie jej wykonywania, przy użyciu parametru arguments.
Argumenty są zawsze przekazywane jako tablica ciągów. Użytkownik jest odpowiedzialny za zapewnienie, że argumenty określone w kodzie UDF są zgodne z argumentami przekazanymi podczas uruchamiania UDF. Użytkownik powinien również upewnić się, że argumenty są prawidłowo parsowane do oczekiwanego typu danych w czasie wykonywania.
export function main(arg1, arg2) {
// Your JavaScript code here
}
Interfejs API języka JavaScript
Kod JavaScript UDF jest wykonywany w środowisku piaskownicy, która zapewnia ograniczony zestaw interfejsów API.
Możesz użyć wszystkich standardowych funkcji globalnych, obiektów i wartości języka JavaScript. Można również użyć globalnego obiektu ccf, aby uzyskać dostęp do określonych funkcji i narzędzi udostępnianych przez platformę Confidential Consortium Framework (CCF), takich jak funkcje pomocnika kryptografii i akcesory tabel rejestru.
Dokumentacja referencyjna interfejsu CCF dokumentuje pełny interfejs API obiektu globalnegoccf.
Dostęp do informacji kontekstowych bieżącego żądania można również uzyskać przy użyciu obiektu globalnego context . Ten obiekt zapewnia dostęp do metadanych żądania, które pochodzą z wykonania funkcji (context.request) i identyfikatora użytkownika obiektu wywołującego funkcję (context.userId). W przypadku hooków transakcji identyfikator kolekcji i zawartość transakcji powiązana z operacją zapisu są również dodawane do context obiektu (context.collectionId i context.contents odpowiednio).
Poniższy fragment kodu przedstawia kilka podstawowych przykładów użycia interfejsu API języka JavaScript:
export function main(args) {
// Basic instructions
const a = 1 + 1;
// Basic statements
if (a > 0) {
console.log("a is positive");
} else {
console.log("a is negative or zero");
}
// Parse the string argument as a JSON object
JSON.parse(args);
// Logging utilities
console.log("Hello world");
// Math utilities
Math.random();
// CCF cryptography utilities
ccf.crypto.digest("SHA-256", ccf.strToBuf("Hello world"));
// Write to a custom ledger table
ccf.kv["public:mytable"].set(ccf.strToBuf("myKey"), ccf.strToBuf("myValue"));
// Read from a custom ledger table
ccf.bufToStr(ccf.kv["public:mytable"].get(ccf.strToBuf("myKey")));
// Read from the ledger entry table
ccf.kv["public:confidentialledger.logs"].get(ccf.strToBuf("subledger:0"));
// Get the request metadata that originated the function execution
const requestMetadata = context.request;
// Get the collection ID and transaction content (for transaction hooks only)
const collectionId = context.collectionId;
const contents = context.contents;
// Throw exceptions
throw new Error("MyCustomError");
}
Wskazówka
Aby uzyskać więcej informacji na temat sposobu użycia map rejestru do przechowywania i pobierania danych, zobacz dokumentację programu CCF dotyczącą interfejsu API magazynu Key-Value.
Uwaga / Notatka
Importowanie modułów nie jest obsługiwane w funkcjach zdefiniowanych przez użytkownika. Kod JavaScript musi być samodzielny i nie może polegać na zewnętrznych bibliotekach ani modułach. Internetowe interfejsy API również nie są obecnie obsługiwane.
Zarządzanie funkcjami zdefiniowanymi przez użytkownika
Aplikacje rejestru poufnego platformy Azure udostępniają dedykowany interfejs API CRUD do tworzenia, odczytywania, aktualizowania i usuwania jednostek UDF. Funkcje zdefiniowane przez użytkownika są bezpiecznie przechowywane w rejestrze i mogą być dostępne wyłącznie dla aplikacji rejestru.
Uwaga / Notatka
Funkcje zdefiniowane przez użytkownika i punkty końcowe zdefiniowane przez użytkownika (UDE) to wzajemnie wykluczające się funkcje. Nie można tworzyć ani uruchamiać funkcji zdefiniowanych przez użytkownika (UDF), jeśli zdefiniowano UDE, i na odwrót. Aby przełączyć się między nimi, postępuj zgodnie z instrukcjami w temacie Przełączanie między funkcjami zdefiniowanymi przez użytkownika i rozszerzeniami zdefiniowanymi przez użytkownika.
Tworzenie lub aktualizowanie funkcji zdefiniowanej przez użytkownika
PUT /app/userDefinedFunctions/myFunction
{
"code": "export function main() { return 'Hello World'; }"
}
Ważne
Do utworzenia lub zaktualizowania UDF wymagana jest rola administratora.
Pobierz funkcję zdefiniowaną przez użytkownika
GET /app/userDefinedFunctions/myFunction
Lista funkcji zdefiniowanych przez użytkownika
GET /app/userDefinedFunctions
Usuń funkcję zdefiniowaną przez użytkownika
DELETE /app/userDefinedFunctions/myFunction
Ważne
Rola administratora jest wymagana do usunięcia funkcji zdefiniowanej przez użytkownika.
Uwaga / Notatka
Usunięcie funkcji zdefiniowanej przez użytkownika (UDF) powoduje, że jednostka zostaje usunięta tylko z aktualnego stanu rejestru. Każda usunięta funkcja zdefiniowana przez użytkownika jest zawsze zachowywana w historii niezmiennej księgi rozrachunkowej (jako każda zatwierdzona transakcja).
Limits
Azure confidential ledger ogranicza liczbę funkcji zdefiniowanych przez użytkownika w rejestrze, długość identyfikatorów UDF i rozmiar kodu UDF. Aby zapoznać się z bieżącymi limitami i sposobem ich wymuszania, zobacz Azure Confidential Ledger limits.
Uruchamianie funkcji zdefiniowanych przez użytkownika
Po utworzeniu poufnego rejestru platformy Azure użytkownicy mogą wykonywać funkcję zdefiniowaną przez użytkownika jako funkcję autonomiczną lub jako hak transakcji związany z operacją zapisu. Każde wykonanie funkcji zdefiniowanej przez użytkownika (UDF) jest uruchamiane w oddzielnym środowisku uruchomieniowym i sandboxie, co oznacza, że wykonanie UDF jest odizolowane od innych UDF-ów lub innych operacji rejestru.
Wykonywanie UDF można kontrolować przy użyciu opcjonalnych właściwości, które można określić wewnątrz żądania. Obecnie obsługiwane właściwości to:
arguments: tablica ciągów znaków, które reprezentują argumenty przekazywane do funkcji zdefiniowanej przez użytkownika (UDF). Argumenty są przekazywane w tej samej kolejności, w której są zdefiniowane w kodzie UDF. Wartość domyślna to pusta tablica.exportedFunctionName: nazwa wyeksportowanej funkcji, która ma być wywoływana podczas wykonywania. Jeśli nie zostanie określony, wartość domyślna tomain.runtimeOptions: obiekt, który określa opcje środowiska uruchomieniowego dla wykonywania funkcji zdefiniowanej przez użytkownika, opisane w poniższej tabeli.
| Option | Description | Domyślnie | Dozwolone wartości |
|---|---|---|---|
max_heap_bytes |
Maksymalny rozmiar sterty w bajtach. | 104 857 600 (100 MiB) | Rozmiar sterty jest obecnie stały na 100 MiB. Inne wartości tego nie zmieniają. |
max_stack_bytes |
Maksymalny rozmiar stosu w bajtach. | 1 048 576 (1 MiB) | 1048 576 do 10 485 760 (10 MiB) |
max_execution_time_ms |
Maksymalny czas wykonania w milisekundach. | 5 000 (5 sekund) | Od 5000 do 10 000 (10 sekund) |
log_exception_details |
Czy rejestrować szczegóły wyjątku. | false |
true lub false |
return_exception_details |
Określa, czy w odpowiedzi mają być zwracane szczegóły wyjątku. | true |
true lub false |
Wartości poza dozwolonym zakresem nie powodują błędu. Zamiast tego rejestr używa najbliższej dozwolonej wartości.
Funkcje autonomiczne
Funkcja UDF może być wykonywana bezpośrednio przy użyciu interfejsu POST /app/userDefinedFunctions/{functionId}:execute API.
POST /app/userDefinedFunctions/myFunction:execute
{}
Treść żądania może służyć do określania opcjonalnych parametrów wykonywania, takich jak argumenty funkcji i właściwości środowiska uruchomieniowego języka JavaScript.
POST /app/userDefinedFunctions/myFunction:execute
{
"arguments": ["arg1", "arg2"],
"exportedFunctionName": "myMainFunction",
"runtimeOptions": {
"max_stack_bytes": 2097152,
"max_execution_time_ms": 8000,
"log_exception_details": true,
"return_exception_details": true
}
}
Odpowiedź wskazuje rezultat wykonania funkcji UDF (powiodło się lub nie powiodło się). Jeśli funkcja UDF powiodła się, odpowiedź zawiera wartość zwróconą przez funkcję w formacie tekstowym (jeśli istnieje).
{
"result":
{
"returnValue": "MyReturnValue"
},
"status": "Succeeded"
}
Jeśli funkcja zdefiniowana przez użytkownika nie powiodła się, odpowiedź zawiera komunikat o błędzie ze szczegółowym śladem stosu.
{
"error": {
"message": "Error while executing function myFunction: Error: MyCustomError\n at myMainFunction (myFunction)\n"
},
"status": "Failed"
}
Ważne
Rola współautora jest wymagana do wykonania funkcji zdefiniowanej przez użytkownika.
Zaczepy transakcji
Funkcja UDF może być również wykonywana jako hak przedwstępny (pre-hook) lub jako hak końcowy (post-hook) po zapisaniu wpisu w księdze w ramach API zapisu księgi (POST /app/transactions). Hooki są uruchamiane w tym samym kontekście co operacja zapisu, co oznacza, że wszystkie dane zapisane w rejestrze przez hooki są automatycznie uwzględniane w tej samej transakcji zapisu.
Treść żądania zapisu może służyć do określenia dowolnych identyfikatorów UDF, które mają być wykonywane jako haki przednie i końcowe.
POST /app/transactions?collectionId=myCollection
{
"contents": "myValue",
"preHooks": [
{
"functionId": "myPreHook"
}
],
"postHooks": [
{
"functionId": "myPostHook"
}
]
}
Ważne
Hooki muszą być jawnie zdefiniowane w treści żądania dla operacji zapisu. Ogólnie rzecz biorąc, funkcje zdefiniowane przez użytkownika nie mogą być uruchamiane automatycznie dla każdej operacji zapisu po utworzeniu.
Dla każdego haka można określić dowolne opcjonalne właściwości wykonywania. Przykład:
POST /app/transactions?collectionId=myCollection
{
"contents": "myValue",
"preHooks": [
{
"functionId": "myPreHook",
"properties": {
"arguments": [
"arg1",
"arg2"
],
"exportedFunctionName": "myMainFunction",
"runtimeOptions": {
"max_stack_bytes": 2097152,
"max_execution_time_ms": 8000,
"log_exception_details": true,
"return_exception_details": true
}
}
}
],
"postHooks": [
{
"functionId": "myPostHook",
"properties": {
"arguments": [
"arg1"
],
"exportedFunctionName": "myMainFunction",
"runtimeOptions": {
"max_stack_bytes": 2097152,
"max_execution_time_ms": 8000,
"log_exception_details": true,
"return_exception_details": true
}
}
}
]
}
Hooki są zawsze wykonywane w kolejności, w jakiej są podane w treści żądania. Liczba wstępnych haków i końcowych haków w żądaniu jest ograniczona. Aby zapoznać się z bieżącymi limitami, zobacz limity usługi Azure Confidential Ledger.
W przypadku niepowodzenia przygotowania wstępnego lub kroku końcowego, cała transakcja zostanie przerwana. W takim przypadku odpowiedź zawiera komunikat o błędzie z przyczyną błędu:
{
"error": {
"code": "InternalError",
"message": "Error while executing function myPreHook: Error: MyCustomError\n at myMainFunction (myPreHook)\n"
}
}
Uwaga / Notatka
Nawet jeśli wielokrotne hooki się powiodą, transakcja nadal może zakończyć się niepowodzeniem, jeśli którykolwiek ze zdefiniowanych pre-hooków lub post-hooków nie zostanie pomyślnie uruchomiony do ukończenia.
Wskazówka
Funkcja UDF może być ponownie użyta jako element wstępny i punkt zaczepienia w tym samym żądaniu i wywoływana wiele razy.
Przykłady
W tej sekcji przedstawiono kilka praktycznych przykładów używania funkcji zdefiniowanych przez użytkownika (UDF) w usłudze Azure Confidential Ledger. W poniższych przykładowych scenariuszach przyjęto założenie, że używasz usługi Azure Confidential Ledger do przechowywania transakcji bankowych różnych użytkowników banku.
Kontekst
Aby przechować transakcję bankową użytkownika, można użyć istniejącego interfejsu API do zapisu rejestru: wartość transakcji stanowi zawartość wpisu rejestru, a identyfikator użytkownika może być kolekcją lub kluczem, gdzie zawartość jest zapisywana.
POST /app/transactions?collectionId=John
{
"contents": "10"
}
HTTP/1.1 200 OK
Ponieważ nie ma walidacji zawartości wejściowej, można zapisać wartość nieliczbową jako zawartość. Na przykład to żądanie powiedzie się, nawet jeśli wartość zawartości nie jest liczbą:
POST /app/transactions?collectionId=Mark
{
"contents": "This is not a number"
}
HTTP/1.1 200 OK
Procedury wstępne na potrzeby walidacji danych
Aby upewnić się, że dane transakcji są zawsze liczbą, utwórz funkcję zdefiniowaną przez użytkownika, aby sprawdzić dane wejściowe. Poniższy pre-hook sprawdza, czy wartość zawartości jest liczbą, i zgłasza błąd, jeśli nią nie jest.
PUT /app/userDefinedFunctions/validateTransaction
{
"code": "export function main() { if (isNaN(context.contents)) { throw new Error('Contents is not a number'); } }"
}
HTTP/1.1 201 CREATED
Za pomocą wstępnego haka w żądaniu zapisu można wymusić, że dane wejściowe odpowiadają oczekiwanemu formatowi. Poprzednie żądanie kończy się teraz niepowodzeniem zgodnie z oczekiwaniami:
POST /app/transactions?collectionId=Mark
{
"contents": "This is not a number",
"preHooks": [
{
"functionId": "validateTransaction"
}
]
}
HTTP/1.1 500 INTERNAL_SERVER_ERROR
{
"error": {
"code": "InternalError",
"message": "Error while executing function validateTransaction: Error: Contents is not a number\n at main (validateTransaction)\n"
}
}
Prawidłowe żądania zawierające wartości liczbowe zakończą się sukcesem zgodnie z oczekiwaniami.
POST /app/transactions?collectionId=Mark
{
"contents": "30",
"preHooks": [
{
"functionId": "validateTransaction"
}
]
}
HTTP/1.1 200 OK
Post-hooks na potrzeby wzbogacania danych
Gdy użytkownicy wykonują nowe transakcje bankowe, chcemy rejestrować, gdy transakcja jest wyższa niż określony próg ze względów inspekcji. Element post-hook może służyć do zapisywania niestandardowych metadanych w rejestrze po operacji zapisu w celu wskazania, czy transakcja była wyższa niż określony próg.
Na przykład można utworzyć funkcję użytkownika w celu sprawdzenia wartości transakcji i zapisania fikcyjnego komunikatu ("Alert" dla wysokich wartości, "Normalny" w przeciwnym razie) przez użytkownika wprowadzającego do niestandardowej tabeli rejestru (payment_metadata), jeśli wartość jest większa niż 50.
PUT /app/userDefinedFunctions/detectHighTransaction
{
"code": "export function main() { let value = 'Normal'; if (context.contents > 50) { value = 'Alert' } ccf.kv['public:payment_metadata'].set(ccf.strToBuf(context.collectionId), ccf.strToBuf(value)); }"
}
HTTP/1.1 201 CREATED
Po pomyślnym utworzeniu funkcji zdefiniowanej przez użytkownika można go użyć w nowych żądaniach zapisu:
POST /app/transactions?collectionId=Mark
{
"contents": "100",
"preHooks": [
{
"functionId": "validateTransaction"
}
],
"postHooks": [
{
"functionId": "detectHighTransaction"
}
]
}
HTTP/1.1 200 OK
POST /app/transactions?collectionId=John
{
"contents": "20",
"preHooks": [
{
"functionId": "validateTransaction"
}
],
"postHooks": [
{
"functionId": "detectHighTransaction"
}
]
}
HTTP/1.1 200 OK
Samodzielne funkcje zdefiniowane przez użytkownika dla niestandardowych kwerend
Aby sprawdzić najnowsze wartości zapisane w niestandardowej tabeli payment_metadata przy użyciu procedury post-hook, można utworzyć funkcję zdefiniowaną przez użytkownika w celu odczytania wartości z tabeli przy użyciu wejściowego identyfikatora użytkownika.
PUT /app/userDefinedFunctions/checkPaymentMetadataTable
{
"code": "export function main(user) { const value = ccf.kv['public:payment_metadata'].get(ccf.strToBuf(user)); if (value === undefined) { throw new Error('UnknownUser'); } return ccf.bufToStr(value); }"
}
HTTP/1.1 201 CREATED
Dzięki bezpośredniemu uruchomieniu zdefiniowanej przez użytkownika funkcji (UDF) można sprawdzić najnowszą wartość zarejestrowaną w niestandardowej tabeli metadanych dla danego użytkownika.
W przypadku użytkowników z niedawną wysoką transakcją funkcja UDF zwraca wartość "Alert", jak oczekiwano.
POST /app/userDefinedFunctions/checkPaymentMetadataTable:execute
{
"arguments": [
"Mark"
]
}
HTTP/1.1 200 OK
{
"result": {
"returnValue": "Alert"
},
"status": "Succeeded"
}
W przypadku użytkowników z ostatnimi niskimi transakcjami funkcja UDF zwraca wartość "Normal" zamiast tego.
POST /app/userDefinedFunctions/checkPaymentMetadataTable:execute
{
"arguments": [
"John"
]
}
HTTP/1.1 200 OK
{
"result": {
"returnValue": "Normal"
},
"status": "Succeeded"
}
W przypadku użytkowników, którzy nie mają żadnego wpisu w tabeli niestandardowej, funkcja UDF zgłasza błąd zdefiniowany w kodzie UDF.
POST /app/userDefinedFunctions/checkPaymentMetadataTable:execute
{
"arguments": [
"Jane"
]
}
HTTP/1.1 200 OK
{
"error": {
"message": "Error while executing function checkPaymentMetadataTable: Error: UnknownUser\n at main (checkPaymentMetadataTable)\n"
},
"status": "Failed"
}
Rozważania
Transakcyjne haki są obecnie obsługiwane tylko dla API
POST /app/transactionspodczas dodawania nowego wpisu do rejestru.Funkcje zdefiniowane przez użytkownika i haki są zawsze wykonywane w podstawowej repliki rejestru, aby zapewnić kolejność transakcji i silną spójność.
Wykonywanie kodu UDF jest zawsze opakowane w jedną transakcję atomową. Jeśli logika języka JavaScript w UDF ukończy się bez żadnych wyjątków, wszystkie operacje w ramach UDF są zatwierdzane w rejestrze. Jeśli zostanie zgłoszony jakikolwiek wyjątek, wszystkie transakcje zostaną wycofane. Podobnie, pre-hooks i post-hooks są wykonywane w tym samym kontekście operacji zapisu, do której są zarejestrowane. Jeśli wstępny lub końcowy punkt kontroli zakończy się niepowodzeniem, cała transakcja zostanie przerwana i do rejestru nie zostanie dodany żaden wpis.
Ze względów bezpieczeństwa funkcje zdefiniowane przez użytkownika mogą uzyskiwać dostęp tylko do tabel aplikacji CCF i nie mogą uzyskiwać dostępu do wewnętrznych tabel księgi oraz tabel zarządzania ani innych wbudowanych tabel. Tabele rejestru, w których wpisy są zapisywane (
public:confidentialledger.logsdla rejestrów publicznych iprivate:confidentialledger.logsprywatnych rejestrów) są tylko do odczytu.Liczba pre-hooków i post-hooków, które można uruchomić w ramach pojedynczej transakcji zapisu, jest ograniczona. Aby zapoznać się z bieżącymi limitami, zobacz limity usługi Azure Confidential Ledger.
Opcja
max_execution_time_msśrodowiska uruchomieniowego ogranicza czas wykonywania funkcji zdefiniowanej przez użytkownika i hooka. Wartości domyślne i maksymalne opisano w Running UDFs. Jeśli funkcja działa dłużej niż limit, operacja zostanie przerwana i zostanie zwrócony błąd.