腾讯云新产品“云开发”尝鲜体验-深蓝源码网


时间: 2020-09-03 00:08:26 人气: 2276 评论: 0

最近用云开发写仿了一个很古老的小游戏 http://stonelf.gitee.io/letter/letter.html 大家可以点进去玩一下。分享一下过程中踩的一些坑。

云开发(Tencent Cloud Base,TCB)是腾讯云为移动开发者提供的一站式后端云服务,可以看作是云函数SCF的升级版。

作为推进serverless的急先锋,SCF提供了弹性的计算能力,也能通过api网关提供弹性的接入能力,但是SCF服务里面不包括后台数据库,因此虽然你可以通过SDK连接到云数据库,但是始终要多关心一个数据库Server,这让我们在说起serverless时,有时显得不够原教旨主义。

而TCB给开发者提供了一个免费和几乎免维护的的no-sql数据库(可以付费升级),这就让原教旨主义的无服务器开发的有了更多的可玩性。此外还很贴心的提供了容易上手的web端、小程序端和服务器端的SDK,让玩转TCB的门槛大大降低。尤其是有一套包装好的服务器端推送的SDK实现(见 数据库web端SDK 的最后一段《数据库实时推送》),可以很方便的开发实时应用。

由于闲闲还在美国幼儿园“留学”,这几天想复刻一个异地互动的flash游戏letters,正好可以用得上这两个特性。

letters是一个很傻的游戏,任何人都可以访问网站看到当前的字母排列,然后可以在屏幕上拖动字母,其他正在访问网页的人会即时看到字母被拖走了,因此也可以多人合作来把字母排列成特定的样子,或者相互搞破坏偷走别人的字母让他拼不成想要的样子。原游戏基于flash实现,现在已经难以怀旧了。重新开发这个游戏除了实现字母拖放互动之外,还想支持现代浏览器和平板,同时还想允许把一个字母换成别的字母,在换掉的时候别人的浏览器上也要实时显示出变化。

实现上很简单:

首先是实现一些基础的页面上的拖放逻辑,并兼容pad。为了兼容不同的显示设备和不同的浏览器大小,字体要随着屏幕宽度缩放,而位置全部要采用百分比定位。这是纯前端部分的工作,可以在文末的连接中跳转到游戏网页上查看源码。

然后就是需要捕获到每次拖放结束的事件,把被拖放的字母的新位置发送给后端的云函数,这部分的代码很简单,拼凑一个http post请求把要发送的数据丢到body里面就好。

function sendData(data){
	fetch("//service-j3t56zj5-1258721286.ap-shanghai.apigateway.myqcloud.com/release/", {
		cache: "no-cache",
		method: 'POST',
		headers: {
			'Accept': 'application/json',
			'Content-Type': 'application/json'
		},
		body: JSON.stringify(data)
	}).then(function(response) {
		return response.json()
	}).then(function(json) {
		if (isNaN(json.errorCode)) {
			console.log("发送成功")
		} else {
			console.log(JSON.stringify(json))
		}
	}).catch(function(ex) {
		console.log('parsing failed', ex)
	})
}

后端的服务程序也很简单,接收到更新的字母后往数据库里面写。不过要考虑到第一个进来玩的人由于数据库里什么都没有,要生成一点原始数据给他玩。

'use strict';
const app = require("tcb-admin-node");
const chars = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9","?","?","?","?","?","?","?","?","?","?","❤️","?","?"]

exports.main = async (event, context, callback) => {
    console.log("\nevent.body:"+event.body)
    let parameters = JSON.parse(event.body),id=-1,x=-1,y=-1,c='';
    if(!!parameters){
        if(!isNaN(parameters["id"])){
            id=parseInt(parameters["id"]);
        }
        if(!isNaN(parameters["x"])){
            x=parameters["x"]-0;
        }
        if(!isNaN(parameters["y"])){
            y=parameters["y"]-0;
        }
        if(parameters["char"] && parameters["char"].length<3){
            c=parameters["char"]
        }
    }
    app.init({env: 'game-acebe0'})    
    const db = app.database();
    const _ = db.command
    let collection = db.collection('game');
    let all = collection.where({char:_.neq('')})
    let data = (await all.orderBy("_id", "asc").get()).data
    if(!data){
        await db.createCollection("game")
        collection = db.collection('game');
        data = [];
    }
    if(data.length<chars.length){ 
        var dataHash = {};
        for(var i=0;i<data.length;i++){
            dataHash[data[i]["_id"]]=true;
        }
        for(let i=0;i<chars.length;i++){
            if(!dataHash[i]){
                let t = {
                    _id:i,
                    char:chars[i],
                    x:6*(i%15)+5,
                    y:7*Math.floor(i/15),
                    color:Math.floor(Math.random()*256*256*256)
                }
                collection.add(t)
                data.push(t)
            }
        }
    }
    if(id>=0 && id<chars.length){//id 合法
        let query =collection.where({"_id":id-0})
        if(x>=0 && x<=100 && y>=0 && y<=100 && c.length==0){ //坐标合法
           let now = Date.now();
            let q=await query.update({"x":x,"y":y})
            console.log("\n 更新时间"+(Date.now()-now)+"毫秒,更新了"+q.updated+"条记录")
            data[id]["x"]=x
            data[id]["y"]=y
        }
        if(c && c.length>0){
            console.log("change char")
            await query.update({"char":c})
        }
    }
    return data
}

TCB的云函数和SCF的一样可以通过api-gateway提供http/https接入能力,只是不像SCF那样可以直接在云函数里面添加api-gateway,而是需要在同服务区的api-gateway里面去把cloud function绑定到api的后端配置中。如果不熟悉api-gateway配置也可以直接把TCB的云函数代码粘贴到SCF的编辑器里面当普通的云函数配置运行,然后就可以在函数服务的触发方式里面添加api-gateway并一步到位的发布服务了。TCB的服务器SDK在SCF中不但工作良好,而且beta用户还可以启用依赖自动安装这样的黑科技,连开发的“服务器”都不需要,真正实现原教旨主义的serverless。唯一要注意的是TCB和SCF的云函数入口有exports.main_handler 和 exports.main 的写法差异。

这里我遇到了云开发的第一个大坑:写初始数据的时候无法批量写入。这就导致我只能一条一条的写入,而很多条数据如果串行写入的话等待数据库返回的时间就会被累加,任何网络抖动都会导致整个函数超时退出。如果并行写入的话会超过免费用户可用的数据库连接数上限导致部分写失败。刚开始我每次检查到数据库的初始数据不完整就重新初始化,然后又一次大量的写入导致部分失败……10分钟不到就把一整天的写操作限额用光了。

一个填坑方案是等待云开发的批量写入接口放出来,不过我想到了 《云原生应用的“十二要素”》中大家一再强调的一个原则:

面向失败的设计:

……大多数云计算的基础设施天生就是短暂的,与本地环境的硬件相比,也更容易出现故障。结合我们大多数人在设计分布式系统时所遵循的原则,你必须设计出能够容忍服务消失或者被重新部署的系统。

是的,我们可以并且应该在设计上让系统容忍这个错误并继续良好运作。具体讲,我先一股脑把所有的初始数据同步丢进去写数据库然后基于部分成功的结果让系统运作起来,然后在下次函数运行的时候看看哪些操作写失败了,再补写一下。通常补写两三次以后就全部都成功了。

在写操作完成后,需要让所有的网页端侦听到数据库发生了什么变化,并把这些变化用动画表现到网页上。参考SDK文档,很容易就用webSDK实现了网页端到侦听:

fetch("//service-1c18mywx-1258721286.ap-shanghai.apigateway.myqcloud.com/release/").then(
	(response) => {
		return response.json
						 技术沙龙 教程文章 热点综合					

评论