Uptime website merupakan salah satu hal yang menjadi elemen penting dalam pengembangan sebuah sistem. Selain itu, uptime
juga merupakan salah satu nilai market yang saat krusial untuk bisnis.
Khususnya dengan teknologi yang semakin berkembang ini, banyak sekali layanan DevOps seperti layanan CI/CD sudah menjadi
bagian yang tidak bisa lepas dari development pipeline suatu aplikasi.
Salah satu penyedia layanan source control yaitu GitHub juga memiliki layanan CI yang dapat digunakan secara cuma-cuma
(GitHub Actions) . Kamu bisa menggunakan CI ini untuk membuat pipeline aplikasi kamu lebih streamlined.
GitHub Actions yang merupakan layanan CI, biasanya hanya digunakan untuk melakukan build dan test pada sistem
aplikasi, tetapi, bagaimana jika GitHub Actions digunakan sebagai layanan untuk memonitor uptime website atau API?
GitHub Actions… untuk Functions?
Mungkin terdengar asing, untuk apa kita menggunakan CI untuk memonitor uptime website? Jawabannya penulis beberapa pekan
lalu mengikuti GitHub Actions Hackathon yang diselenggarakan oleh dev.to. Platform blogging dev.to mengadakan
hackathon untuk membuat inovasi unik dengan menggunakan GitHub Actions dan ini adalah submisi penulis.
Kembali ke topik, bagaimana caranya layanan CI bisa digunakan untuk memonitor uptime? Sedangkan untuk monitoring uptime
pasti dibutuhkan basis data untuk menyimpan hasil pengecekan uptime, solusinya?
Untungnya, GitHub punya semua tool yang dibutuhkan untuk mencapai tujuan ini!
GitHub Repo, untuk menyimpan perubahan uptime.
GitHub Actions, untuk mengecek dan menyimpan perubahan uptime.
GitHub Pages, untuk menampilkan data uptime.
Mungkin ini pertama kalinya kamu mendapati penggunaan Git sebagai basis data dan CI sebagai CRON job. Yap, ide bisa
muncul dari mana saja, yang penting kita bisa selalu kreatif menggunakan sumber daya yang kita miliki.
Membuat repo
Pada tutorial ini kita akan menggunakan NodeJS sebagai backend yang nantinya akan mengecek website kita dan akan
menyimpan riwayat uptime website kita.
Kita akan menggunakan library axios pada backed untuk melakukan request ke server yang akan kita monitor dan
Vue.js sebagai framework untuk UI nya.
constfs=require('fs');constaxios=require('axios').default;// configs
constconfig=Object.freeze({maxIncidents:6,userAgent:'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.83 Safari/537.36 Edg/85.0.564.44'});constmain=async()=>{constmonitoredUrls=JSON.parse(fs.readFileSync('data/monitored.json','utf-8'));constcheckResult=[];constreqs=[];// run request
console.log("Checking services...");for(leti=0;i<monitoredUrls.length;i++){constitem=monitoredUrls[i];constopt={url:item.uri,responseType:'text',transformResponse:[],timeout:1000*5,headers:{'User-Agent':config.userAgent}};console.debug(`Checking ${item.desc}, env: ${item.env}`);constreq=axios(opt).then(response=>{if(response.status>=400||!response.data||response.data.includes("Application is not available")){checkResult.push({...item,status:"error",date:newDate().toISOString()});}else{checkResult.push({...item,status:"ok",date:newDate().toISOString()});}}).catch(_=>{checkResult.push({...item,status:"error",date:newDate().toISOString()});});reqs.push(req);}awaitPromise.all(reqs);// load latest data
console.log("Fetching last data...");constlastIncidentData=fs.readFileSync('data/last_incident.json','utf-8');letlastIncident;if(lastIncidentData){lastIncident=JSON.parse(lastIncidentData);}else{lastIncident={date:newDate().toISOString(),incident:"All monitored service is up.",status:"ok",services:[]};}// save global result
console.log("Checking latest incident...");constcheckedOk=checkResult.filter(x=>x.status==="ok").length;constlastOk=lastIncident.services.filter(service=>service.status==="ok").length;if(checkedOk!=lastOk){lastIncident.date=newDate().toISOString();}if(lastOk!=checkResult.length){constrepos=checkResult.filter(x=>x.status==="error").map(y=>`${y.desc}:${y.env}`);lastIncident.incident=`${repos.join(', ')} is down.`;lastIncident.status="error";}else{lastIncident.incident=`All monitored service is up.`;lastIncident.status="ok";}// save services status
console.log("Saving incidents...");checkResult.forEach(item=>{constcurrentServiceIndex=lastIncident.services.findIndex(x=>x.desc==item.desc&&x.env==item.env);constcurrentService=lastIncident.services[currentServiceIndex\];if(!currentService){lastIncident.services.push({desc:item.desc,env:item.env,status:item.status,incidents:[{date:item.date,status:item.status}]});}else{constcurrentServiceLastIncident=currentService.incidents[0];currentService.status=item.status;if(currentServiceLastIncident.status!==item.status){if(lastIncident.services[currentServiceIndex].incidents.length>=config.maxIncidents){lastIncident.services[currentServiceIndex].incidents.pop();}lastIncident.services[currentServiceIndex].incidents.unshift({date:item.date,status:item.status});};}});// save updated data
console.log("Serializing...");fs.writeFileSync('data/last_incident.json',JSON.stringify(lastIncident,null,2));}// bootstrap
main().catch(error=>console.error(error));
Kode di atas akan melakukan beberapa proses berikut:
Membaca data website apa saja yang akan dimonitor pada file monitored.json.
Melakukan HTTP request ke URI yang dibaca dari file JSON.
Menyimpan hasil pengecekan ke file last_incident.json.
Selanjutnya kamu harus mendefinisikan URI mana yang akan dimonitor oleh sistem ini. Buat folder data, kemudian buat
file monitored.json.
Nah file ini nantinya akan menyimpan URI mana saja yang akan dicek dan dimonitor. Tambahkan semua URI yang ingin kamu
cek di sini.
Untuk backend hanya sampai di sini. Selanjutnya kamu akan setting GitHub Actions agar mengeksekusi kode ini setiap lima
menit. Waktu ini merupakan batas minimum untuk jadwal eksekusi kode pada CI.
Buat folder .github/workflows, kemudian buat file node.js.yml.
name:Node.js CIon:workflow\_dispatch:schedule:- cron:'*/5 * * * *'jobs:build:runs-on:ubuntu-lateststeps:- uses:actions/checkout@v2- name:Use Node.jsuses:actions/setup-node@v1with:node-version:12.x- run:npm install- run:npm start- name:Commit and push if changedrun:| git add .
git diff
git config --global user.email "github-action-bot@example.com"
git config --global user.name "GitHub Action Bot"
git commit -m "Updated incident" -a || echo "No changes to commit"
git push
Workflow di atas akan mengeksekusi npm install dan npm start, setelah itu workflow ini akan mengeksekusi kode untuk
melakukan commit perubahan yang baru disimpan ke dalam git.
Membuat frontend
Seperti yang sudah disebutkan sebelumnya, bahwa pada frontend kita akan menggunakan Vue.js dan juga Bulma CSS untuk
mempercantik tampilan webnya.
Buat file index.html pada root folder kamu, kemudian salin kode berikut.
constsecond=1000;constminute=second*60;consthour=minute*60;constday=hour*24;varapp=newVue({el:'#app',data:{clock:null,date:null,incident:null,services:null,updateTimer:null},methods:{updateData(){constopt={url:"data/last_incident.json?nokey="+Math.random()\*1000,responseType:"json",headers:{'Cache-Control':'no-cache','Pragma':'no-cache','Expires':'0'}};axios(opt).then(response=>{constlatestData=response.data;this.date=newDate(latestData.date);this.incident=latestData.incident;this.services=latestData.services;this.updateTimer=setInterval(()=>{letnow=newDate().getTime();letdistance=now-this.date;this.clock=prettyClock(distance);},1000);});},statusToMessage(status){returnstatus==="ok"?"Service is up":"Service is down";},prettyDate(date){returnnewDate(date).toLocaleString();}},created(){this.updateData();},beforeDestroy(){clearInterval(this.updateTimer)},});functionprettyClock(distance){return{days:Math.floor(distance/(day)),hours:Math.floor((distance%(day))/(hour)),minutes:Math.floor((distance%(hour))/(minute)),seconds:Math.floor((distance%(minute))/second)};}
Kode di atas merupakan kode untuk membaca data dari file last_incident.json yang terdapat pada repositori yang
nantinya akan menyimpan program ini.
Push sistem ke GitHub
Setelah kamu memiliki semua file yang dibutuhkan, jangan lupa untuk commit semua kode Anda dan push ke repositori GitHub
kamu. Untuk memastikan apakah Actions yang sudah dibuat terdeteksi oleh GitHub Actions, klik tab Actions pada menu
repositori.
Jika menu ini sudah tampil, artinya sistem kamu sudah terdaftar pada GitHub Actions dan akan segera dieksekusi. Tunggu
10-15 menit untuk peluncuran pertama kali. Jika pipeline tidak kunjung aktif, klik Run workflow > Run workflow untuk
menjalankan workflow secara manual.
Siip! Sekarang kamu sudah memiliki web yang dapat memonitor uptime website atau API kamu setiap lima menit sekali,
bahkan tanpa perlu menyewa hosting dan layanan cloud berbayar!
Rekomendasi: UptimeRobot
Tutorial yang dijelaskan di atas hanya merupakan hack atau lebih tepatnya proyek iseng untuk memanfaatkan sistem yang
ada untuk kebutuhan lain. Jika dilihat dari sisi bisnis, kamu pasti butuh laporan yang lebih mendalam mengenai
downtime yang terjadi di aplikasi kamu, tidak hanya sekadar waktu kapan terjadinya downtime.
Maka dari itu penulis sangat menyarankan layanan dari UptimeRobot. Layanan ini merupakan penyedia monitoring uptime
website atau API yang sudah penulis gunakan sangat lama. Layanan ini juga memiliki versi gratis yang bisa langsung kamu
pakai dengan hanya mendaftar di website-nya.
Dasbor UptimeRobot.
Dengan UptimeRobot kamu bisa melihat riwayat downtime dan juga laporan time series kapan terjadi downtime, waktu
respons server, dan bisa memonitor lebih dari satu URI.
Overall, layanan yang sangat bagus dengan fitur dasar yang sesuai dengan kebutuhan. Give it a try!
Semoga artikel kali ini bermanfaat ya teman-teman! #NgodingItuMudah