Jika Anda perlu menentukan beberapa awalan objek dan akhiran untuk pemicu Object Storage Service (OSS) atau mengaitkan lebih dari 10 pemicu dengan bucket OSS, Anda dapat membuat pemicu OSS berbasis EventBridge untuk menanggapi peristiwa seperti unggahan file dengan mudah.
Catatan penggunaan
Pemicu OSS berbasis EventBridge berbeda dari pemicu OSS asli. Perhatikan hal-hal berikut saat membuat pemicu OSS berbasis EventBridge:
Anda dapat mengaitkan maksimal 10 pemicu OSS asli dengan sebuah bucket. Jika Anda ingin mengaitkan lebih banyak pemicu OSS dengan sebuah bucket, gunakan pemicu OSS berbasis EventBridge.
CatatanKami merekomendasikan agar Anda tidak mengaitkan lebih dari 10 pemicu dengan sebuah bucket. Jika membutuhkan lebih banyak pemicu, buat bucket baru dan konfigurasikan pemicu berdasarkan bucket tersebut.
Anda dapat membuat hingga 50 pemicu OSS berbasis EventBridge sesuai dengan batasan sumber daya EventBridge. Untuk informasi lebih lanjut, lihat Batasan.
Tidak diperlukan keunikan semantik untuk pemicu OSS berbasis EventBridge. Parameter Event Type, Object Prefix, dan Object Suffix tidak harus unik.
Anda dapat mengonfigurasi beberapa entri untuk Object Prefix dan Object Suffix. Namun, pencocokan kabur dan pencocokan ekspresi reguler berdasarkan Object Prefix dan Object Suffix tidak didukung.
Pemicu OSS berbasis EventBridge tidak langsung berlaku setelah dibuat. Tunggu sekitar 30 detik sebelum peristiwa OSS dapat memicu fungsi terkait.
Skenario contoh
Anda dapat mengonfigurasi pemicu OSS dengan menetapkan awalan menjadi source dan test, serta akhiran menjadi .rar dan .zip dalam aturan pemicu. Saat file terkompresi disimpan di direktori source atau test di bucket OSS tertentu dan akhiran file adalah .rar atau .zip, fungsi dipicu. Setelah fungsi dieksekusi, file yang telah diekstraksi disimpan di direktori lain pada bucket yang sama.
Sebelum Anda mulai
EventBridge
Function Compute
OSS
Langkah 1: Buat pemicu OSS berbasis EventBridge
Masuk ke Konsol Function Compute. Di panel navigasi kiri, klik Functions.
Di bilah navigasi atas, pilih wilayah. Pada halaman Functions, klik fungsi yang ingin Anda kelola.
Di halaman Detail Fungsi, klik tab Configurations. Di panel navigasi kiri, klik Triggers. Lalu, klik Create Trigger.
Di panel Buat Pemicu, pilih Object Storage Service (OSS) di Event triggers for Alibaba Cloud Services dari daftar drop-down Trigger Type, konfigurasikan parameter lainnya, lalu klik OK. Tabel berikut menjelaskan parameter.
Parameter
Deskripsi
Contoh
Name
Masukkan nama pemicu.
oss-trigger
Version or Alias
Pilih alias atau versi. Nilai default: LATEST. Jika Anda ingin membuat pemicu untuk versi atau alias lain, pilih versi atau alias dari daftar drop-down Version or Alias pada halaman detail fungsi. Untuk informasi lebih lanjut tentang versi dan alias, lihat Kelola versi dan Kelola alias.
LATEST
Bucket Name
Pilih bucket yang Anda buat.
bucket-zh****
Object Prefix
Masukkan awalan nama objek yang ingin Anda cocokkan. Kami merekomendasikan Anda menentukan Awalan Objek dan Akhiran Objek di Function Compute untuk menghindari biaya tambahan yang disebabkan oleh loop bersarang.
Anda dapat mengklik + Add Object Prefix untuk menambahkan lebih banyak entri untuk parameter Object Prefix.
PentingAwalan tidak boleh dimulai dengan garis miring (
/). Jika tidak, pemicu OSS tidak dapat dipicu.source
test
Object Suffix
Masukkan akhiran nama objek yang ingin Anda cocokkan. Kami merekomendasikan Anda menentukan Awalan Objek dan Akhiran Objek di Function Compute untuk menghindari biaya tambahan yang disebabkan oleh loop bersarang.
Anda dapat mengklik + Add Object Suffix untuk menambahkan lebih banyak entri untuk parameter Object Suffix.
png
Event Type
Pilih satu atau lebih peristiwa pemicu. Untuk informasi lebih lanjut tentang definisi tipe peristiwa OSS di Function Compute, lihat Peristiwa OSS.
oss:ObjectCreated:PutObject,oss:ObjectCreated:PostObject, danoss:ObjectCreated:CompleteMultipartUploadEvent Pattern Content
Setelah Anda mengonfigurasi parameter Object Prefix, Object Suffix, dan Event Type, sistem secara otomatis mengonfigurasi parameter ini.
PentingBerhati-hatilah saat Anda memodifikasi parameter Event Pattern Content. Kesalahan operasi dapat menyebabkan kegagalan pemicuan. Sebelum Anda memutuskan apakah akan memodifikasi pola peristiwa, Anda harus memahami aturan pola peristiwa. Untuk informasi lebih lanjut, lihat Pola peristiwa.
{ "source":[ "acs.oss" ] }Invocation Method
Pilih metode yang digunakan untuk memanggil fungsi. Nilai default: Pemanggilan Sinkron.
Sync Invocation: Setelah peristiwa memicu fungsi, Function Compute mengembalikan hasil eksekusi ketika eksekusi selesai. Metode ini cocok untuk berbagai skenario. Untuk informasi lebih lanjut, lihat Pemanggilan sinkron.
Async Invocation: Setelah peristiwa memicu fungsi, Function Compute segera mengembalikan respons dan memastikan bahwa fungsi dieksekusi setidaknya sekali. Namun, hasil eksekusi rinci tidak dikembalikan. Metode pemanggilan ini cocok untuk fungsi yang memiliki latensi penjadwalan tinggi. Untuk informasi lebih lanjut, lihat Ikhtisar.
Pemanggilan Sinkron
Trigger State
Tentukan apakah akan mengaktifkan pemicu segera setelah dibuat. Secara default, Enable Trigger dipilih, yang menunjukkan bahwa pemicu diaktifkan segera setelah dibuat.
N/A
Push Format
Tentukan format data parameter input fungsi. Data dilewatkan menggunakan parameter event fungsi. Nilai valid:
CloudEvents: spesifikasi yang menggambarkan data peristiwa dalam format umum, termasuk deskripsi peristiwa dan data payload peristiwa. Spesifikasi ini digunakan untuk menyederhanakan deklarasi peristiwa dan transmisi antara layanan dan platform yang berbeda.
RawData: spesifikasi yang hanya mengirimkan data payload peristiwa dan tidak mencakup informasi metadata lainnya dalam format CloudEvents.
CatatanPemicu OSS asli dan pemicu OSS berbasis EventBridge menggunakan push formats yang berbeda. Parameter event dari pemicu OSS asli mendukung template OSSEvents, yaitu format event yang dihasilkan oleh OSS.
CloudEvents
Setelah pemicu dibuat, pemicu tersebut ditampilkan di tab Triggers. Untuk memodifikasi atau menghapus pemicu, lihat Manajemen Pemicu.
Langkah 2: Konfigurasikan parameter input fungsi
Sumber peristiwa pemicu OSS berbasis EventBridge diteruskan ke fungsi dalam format CloudEvents, yang bertindak sebagai parameter input. Anda dapat secara manual meneruskan peristiwa ke fungsi untuk memicu fungsi.
Di tab Code halaman detail fungsi, klik ikon
di sebelah Test Function dan pilih Configure Test Parameters dari daftar drop-down.Di panel Configure Test Parameters, klik tab Create New Test Event atau Modify Existing Test Event, masukkan nama peristiwa dan isi peristiwa, lalu klik OK.
Saat peristiwa tertentu terjadi di bucket OSS tertentu, data peristiwa dikirim ke fungsi terikat dalam format JSON. Data peristiwa dilewatkan dalam parameter event ke Function Compute. Kode berikut memberikan contoh:
{ "datacontenttype": "application/json;charset=utf-8", "aliyunaccountid": "143199913****", "data": { "eventVersion": "1.0", "responseElements": { "requestId": "6364D216511B143733C5A67B" }, "eventSource": "acs:oss", "eventTime": "2023-11-04T08:49:26.000Z", "requestParameters": { "sourceIPAddress": "140.205.XX.XX" }, "eventName": "ObjectCreated:PutObject", "userIdentity": { "principalId": "143199913****" }, "region": "cn-hangzhou", "oss": { "bucket": { "name": "bucket-zh***", "arn": "acs:oss:cn-hangzhou:143199913****:bucket-zh***", "virtualBucket": "", "ownerIdentity": "143199913****" }, "ossSchemaVersion": "1.0", "object": { "size": 13, "objectMeta": { "mimeType": "text/plain" }, "deltaSize": 13, "eTag": "59CA0EFA9F5633CB0371BBC0355478D8", "key": "source/a.png" } } }, "subject": "acs:oss:cn-hangzhou:143199913****:bucket-zh***/source/a.png", "aliyunoriginalaccountid": "143199913****", "source": "acs.oss", "type": "oss:ObjectCreated:PutObject", "aliyunpublishtime": "203-11-04T08:49:26.745Z", "specversion": "1.0", "aliyuneventbusname": "default", "id": "6364D216511B143733C5A67B", "time": "2023-11-04T08:49:26Z", "aliyunregionid": "cn-hangzhou" }Tabel berikut menjelaskan bidang dalam peristiwa.
Parameter
Tipe
Contoh
Deskripsi
datacontenttype
String
application/json;charset=utf-8
Tipe konten parameter data. datacontenttype hanya mendukung application/json;charset=utf-8.
aliyunaccountid
String
143199913****
ID akun Alibaba Cloud. Anda dapat memperoleh ID akun Alibaba Cloud di bagian References pada halaman Overview di konsol Function Compute.
data
{}
Konten peristiwa OSS, yang merupakan objek JSON. CloudEvents berisi konteks yang didefinisikan oleh OSS saat peristiwa terjadi. Informasi ini dienkapsulasi dalam parameter data.
subject
String
acs:oss:cn-hangzhou:143199913****:bucket-zh****/source/a.png
Subjek peristiwa.
Format:
acs:oss:<region>:<your_account_id>:<your_bucket>.<region>menunjukkan wilayah yang Anda pilih saat membuat fungsi.<your_account_id>menunjukkan ID akun Alibaba Cloud Anda.<your_bucket>menunjukkan nama bucket yang Anda buat di wilayah yang sama.aliyunoriginalaccountid
String
143199913****
ID akun Alibaba Cloud.
source
String
acs.oss
Sumber peristiwa. Nilainya tetap
acs.oss.type
String
oss:ObjectCreated:PutObject
Tipe peristiwa.
aliyunpublishtime
Timestamp
2023-11-04T08:49:26.745Z
Waktu saat peristiwa diterima.
specversion
String
1.0
Versi spesifikasi CloudEvents.
aliyuneventbusname
String
default
Nama bus peristiwa yang menerima peristiwa.
id
String
6364D216511B143733C5A67B
ID peristiwa.
time
Timestamp
2023-11-04T08:49:26Z
Waktu saat peristiwa terjadi.
aliyunregionid
String
cn-hangzhou
Wilayah tempat peristiwa diterima.
aliyunpublishaddr
String
140.205.XX.XX
Alamat IP server yang menerima peristiwa.
Konfigurasikan bidang data parameter Event berdasarkan kebutuhan bisnis Anda.
userIdentity.principalId: ID akun Alibaba Cloud Anda.region: wilayah yang Anda pilih saat membuat fungsi.oss.bucket.name: nama bucket yang dibuat di wilayah yang sama dengan fungsi.oss.bucket.arn: Nama Sumber Daya Alibaba Cloud (ARN) dari bucket, dalam formatacs:oss:<region>:<your_account_id>:<your_bucket>.<region>menunjukkan wilayah yang Anda pilih saat membuat fungsi.<your_account_id>menunjukkan ID akun Alibaba Cloud Anda.<your_bucket>menunjukkan nama bucket yang Anda buat di wilayah yang sama.oss.bucket.ownerIdentity: ID akun Alibaba Cloud Anda.object.key: objek yang telah Anda unggah ke bucket tujuan.CatatanPastikan objek yang ditentukan ada di bucket yang ditentukan. Jika tidak, fungsi tidak dapat dieksekusi atau eksekusi gagal. Dalam contoh ini, source/a.png digunakan.
Langkah 3: Tulis dan uji fungsi
Setelah Anda membuat pemicu, Anda dapat menulis kode fungsi dan menguji fungsi untuk memverifikasi apakah kode tersebut benar. Saat peristiwa OSS terjadi, fungsi secara otomatis dipicu.
Hindari pemicuan loop dalam kode. Jika tidak, biaya tambahan akan timbul. Misalnya, ketika objek diunggah ke bucket OSS, operasi unggah memicu fungsi. Kemudian, fungsi tersebut menghasilkan satu atau lebih objek dan menulis objek tersebut ke bucket OSS, dan operasi penulisan memicu fungsi lagi. Ini mengarah pada loop. Untuk informasi lebih lanjut, lihat Aturan Pemicuan.
Di tab Code halaman Detail Fungsi, tulis kode di editor kode dan klik Deploy.
Berikut ini menjelaskan persiapan yang harus Anda lakukan dan kode contoh:
CatatanJika Anda ingin membaca data dari dan menulis data ke sumber daya OSS dalam fungsi Anda, kami merekomendasikan agar Anda menggunakan titik akhir internal OSS untuk mengakses sumber daya OSS. Jika Anda menggunakan titik akhir publik, Anda akan dikenakan biaya untuk data yang ditransfer melalui Internet. Untuk informasi lebih lanjut tentang format titik akhir internal OSS, lihat Wilayah dan Titik Akhir.
/* Persiapan: 1. Jalankan perintah berikut di klien untuk membuat file package.json dan menginstal modul jimp. a. Jalankan perintah npm init di klien untuk membuat file package.json. b. Jalankan perintah npm install jimp untuk menginstal modul jimp. 2. Pastikan handler fungsi adalah index.handler. */ 'use strict'; console.log('Loading function ...'); var oss = require('ali-oss'); var fs = require('fs'); var jimp = require("jimp"); module.exports.handler = function (eventBuf, ctx, callback) { console.log('Received event:', eventBuf.toString()); var event = JSON.parse(eventBuf); var ossEvent = event.data; // Wilayah OSS memiliki awalan oss-. Contoh: oss-cn-shanghai. var ossRegion = "oss-" + ossEvent.region; // Buat klien OSS. var client = new oss({ region: ossRegion, /* Pasangan AccessKey dari akun Alibaba Cloud dapat digunakan untuk mengakses semua operasi API. Menggunakan kredensial ini untuk melakukan operasi di Function Compute adalah operasi berisiko tinggi. Kami merekomendasikan agar Anda menggunakan pengguna RAM untuk memanggil operasi API atau melakukan pemeliharaan rutin. Kami merekomendasikan agar Anda tidak menyimpan ID AccessKey dan Rahasia AccessKey di kode proyek Anda. Jika tidak, pasangan AccessKey dapat bocor dan keamanan semua sumber daya di bawah akun Anda dapat terganggu. Dalam contoh ini, ID AccessKey dan Rahasia AccessKey diperoleh dari konteks. */ accessKeyId: ctx.credentials.accessKeyId, accessKeySecret: ctx.credentials.accessKeySecret, stsToken: ctx.credentials.securityToken }); // Dapatkan nama bucket dari peristiwa. client.useBucket(ossEvent.oss.bucket.name); // Gambar yang diproses disimpan ke direktori processed/. var newKey = ossEvent.oss.object.key.replace("source/", "processed/"); var tmpFile = "/tmp/processed.png"; // Dapatkan objek OSS. console.log('Getting object: ', ossEvent.oss.object.key) client.get(ossEvent.oss.object.key).then(function (val) { // Baca isi objek OSS dari cache. jimp.read(val.content, function (err, image) { if (err) { console.error("Failed to read image"); callback(err); return; } // Ubah ukuran gambar dan simpan ke file tmp. image.resize(128, 128).write(tmpFile, function (err) { if (err) { console.error("Failed to write image locally"); callback(err); return; } // Unggah objek OSS yang dibaca ke bucket OSS dan ubah nama objek. console.log('Putting object: ', newKey); client.put(newKey, tmpFile).then(function (val) { console.log('Put object:', val); callback(null, val); return; }).catch(function (err) { console.error('Failed to put object: %j', err); callback(err); return }); }); }); }).catch(function (err) { console.error('Failed to get object: %j', err); callback(err); return }); };# Persiapan: #1. Pastikan bahwa peran yang dikonfigurasi untuk fungsi memiliki izin untuk mengakses OSS. Anda dapat masuk ke konsol RAM dan memberikan peran izin untuk mengakses OSS. #2. Pastikan handler fungsi adalah index.handler. # -*- coding: utf-8 -*- import oss2, json from wand.image import Image def handler(event, context): evt = json.loads(event) creds = context.credentials # Diperlukan oleh OSS sdk # Pasangan AccessKey dari akun Alibaba Cloud dapat digunakan untuk mengakses semua operasi API. Menggunakan kredensial ini untuk melakukan operasi di Function Compute adalah operasi berisiko tinggi. Kami merekomendasikan agar Anda menggunakan pengguna RAM untuk memanggil operasi API atau melakukan pemeliharaan rutin. # Kami merekomendasikan agar Anda tidak menyimpan ID AccessKey dan Rahasia AccessKey ke kode proyek Anda. Jika tidak, pasangan AccessKey dapat bocor dan keamanan semua sumber daya di akun Anda dapat terganggu. # Dalam contoh ini, ID AccessKey dan Rahasia AccessKey diperoleh dari konteks. auth=oss2.StsAuth( creds.access_key_id, creds.access_key_secret, creds.security_token) evt = evt['data'] bucket_name = evt['oss']['bucket']['name'] endpoint = 'oss-' + evt['region'] + '-internal.aliyuncs.com' bucket = oss2.Bucket(auth, endpoint, bucket_name) objectName = evt['oss']['object']['key'] # Gambar yang diproses akan disimpan ke processed/ newKey = objectName.replace("source/", "processed/") remote_stream = bucket.get_object(objectName) if not remote_stream: return remote_stream = remote_stream.read() with Image(blob=remote_stream) as img: with img.clone() as i: i.resize(128, 128) new_blob = i.make_blob() bucket.put_object(newKey, new_blob)/* Persiapan: #1. Pastikan bahwa peran yang dikonfigurasi untuk fungsi memiliki izin untuk mengakses OSS. Anda dapat masuk ke konsol RAM dan memberikan peran izin untuk mengakses OSS. #2. Pastikan handler fungsi adalah index.handler. */ <?php use OSS\OssClient; function handler($event, $context) { $event = json_decode($event, $assoc = true); /* Pasangan AccessKey dari akun Alibaba Cloud dapat digunakan untuk mengakses semua operasi API. Menggunakan kredensial ini untuk melakukan operasi di Function Compute adalah operasi berisiko tinggi. Kami merekomendasikan agar Anda menggunakan pengguna RAM untuk memanggil operasi API atau melakukan pemeliharaan rutin. Kami merekomendasikan agar Anda tidak menyimpan ID AccessKey dan Rahasia AccessKey ke kode proyek Anda. Jika tidak, pasangan AccessKey dapat bocor dan keamanan semua sumber daya di akun Anda dapat terganggu. Dalam contoh ini, ID AccessKey dan Rahasia AccessKey diperoleh dari konteks. */ $accessKeyId = $context["credentials"]["accessKeyId"]; $accessKeySecret = $context["credentials"]["accessKeySecret"]; $securityToken = $context["credentials"]["securityToken"]; $evt = $event['data']; $bucketName = $evt['oss']['bucket']['name']; $endpoint = 'oss-' . $evt['region'] . '-internal.aliyuncs.com'; $objectName = $evt['oss']['object']['key']; $newKey = str_replace("source/", "processed/", $objectName); try { $ossClient = new OssClient($accessKeyId, $accessKeySecret, $endpoint, false, $securityToken); $content = $ossClient->getObject($bucketName , $objectName); if ($content == null || $content == "") { return; } $imagick = new Imagick(); $imagick->readImageBlob($content); $imagick->resizeImage(128, 128, Imagick::FILTER_LANCZOS, 1); $ossClient->putObject($bucketName, $newKey, $imagick->getImageBlob()); } catch (OssException $e) { print($e->getMessage()); } /* Persiapan: 1. Tambahkan dependensi berikut ke file pom.xml. <dependencies> <dependency> <groupId>com.aliyun.fc.runtime</groupId> <artifactId>fc-java-core</artifactId> <version>1.4.1</version> </dependency> <dependency> <groupId>com.aliyun.fc.runtime</groupId> <artifactId>fc-java-event</artifactId> <version>1.2.0</version> </dependency> </dependencies> 2. Pastikan handler fungsi adalah example.App::handleRequest. */ package example; import java.io.*; import java.util.Map; import com.aliyun.fc.runtime.Context; import com.aliyun.fc.runtime.StreamRequestHandler; import com.aliyun.fc.runtime.event.OSSEvent.Event; import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; public class App implements StreamRequestHandler { private static final ObjectMapper mapper = new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); public static final class CloudEvent { public final String id; public final String source; public final String specversion; public final String type; public final String datacontenttype; public final String dataschema; public final String subject; public final String time; public final Map<String, ?> extensions; public final Event data; @JsonCreator public CloudEvent(@JsonProperty("id") String id, @JsonProperty("source") String source, @JsonProperty("specversion") String specversion, @JsonProperty("type") String type, @JsonProperty("datacontenttype") String datacontenttype, @JsonProperty("dataschema") String dataschema, @JsonProperty("subject") String subject, @JsonProperty("time") String time, @JsonProperty("extensions") Map<String, ?> extensions, @JsonProperty("data") Event data) { this.id = id; this.source = source; this.specversion = specversion; this.type = type; this.datacontenttype = datacontenttype; this.dataschema = dataschema; this.subject = subject; this.time = time; this.extensions = extensions; this.data = data; } public String getId() { return this.id; } public String getSource() { return this.source; } public String getSpecversion() { return this.specversion; } public String getType() { return this.type; } public String getDatacontenttype() { return this.datacontenttype; } public String getDataschema() { return this.dataschema; } public String getSubject() { return this.subject; } public String getTime() { return this.time; } public Map<String, ?> getExtensions() { return this.extensions; } public Event getData() { return this.data; } } @Override public void handleRequest( InputStream inputStream, OutputStream outputStream, Context context) throws IOException { CloudEvent cloudEvents = mapper.readValue(inputStream, new TypeReference<CloudEvent>() {}); Event ossEvent = cloudEvents.getData(); context.getLogger().info(String.format("received %s from %s @ %s", ossEvent.eventName, ossEvent.eventSource, ossEvent.region)); outputStream.write(String.format("received %s from %s @ %s", ossEvent.eventName, ossEvent.eventSource, ossEvent.region).getBytes()); outputStream.write(String.format("received bucket %s", ossEvent.oss.bucket.arn).getBytes()); outputStream.write(String.format("received object %s and it's size is %s", ossEvent.oss.object.key, ossEvent.oss.object.size).getBytes()); } }Klik Test Function.
Setelah fungsi dieksekusi, Anda dapat melihat hasilnya di tab Code.
FAQ
Informasi tambahan
Untuk informasi lebih lanjut tentang tipe peristiwa OSS yang dapat Anda konfigurasikan, lihat Peristiwa OSS.
Jika Anda ingin memodifikasi atau menghapus pemicu yang ada, lihat Modifikasi Pemicu.
Masalah terkait pemicu:
Jika Anda ingin memeriksa peristiwa yang memicu fungsi, Anda dapat menentukan sistem untuk mencetak log tipe peristiwa dalam kode Anda. Untuk informasi lebih lanjut, lihat Log.
Jika Anda ingin menggunakan fungsi untuk memanggil fungsi lain, Anda dapat menggunakan operasi API untuk memanggil fungsi atau menggunakan alur kerja fungsi untuk mengatur fungsi. Jika fungsi yang dipanggil memerlukan waktu lama untuk dieksekusi dan melibatkan pemanggilan asinkron, Anda dapat mengonfigurasi layanan tujuan untuk pemanggilan asinkron. Untuk informasi lebih lanjut, lihat Apakah fungsi dapat saling memanggil? dan Konfigurasikan Tujuan untuk Pemanggilan Asinkron.