想想无服务器,使用Pythonic –全部在您的浏览器中!
(好吧,这则新闻已经过了几周了,但是仍然……)
如果您沉迷于整个无服务器的“事物”中 ,您可能已经注意到我们,一个在SLAppForge臭名昭著的人 ,对“无服务器的IDE”感到困惑。 是的,我们已经运行了很长一段时间的Sigma IDE (这是同类产品中的第一个),已经得到了全世界用户的反馈。
我们的标准反馈表中有一个问题: “开发无服务器应用程序时首选的语言是什么?” ; 带有选项Node , Java , Go , C#和一个建议框。 令人惊讶的是(或可能不是),建议框是最受欢迎的选项。 除了两个以外,其他所有“替代”选项都是一个-Python 。
是Python!
我们甚至有一些用户想要取消他们的全新订阅,因为Sigma不像他们期望的那样支持Python。
因此,在我们的路线图会议之一中,整个Python的故事问世了; 我们决定试一试。
在故事发生之前,一些积分要整理好。
Hasangi是我们以前的开发人员之一,最初负责评估在Sigma中支持Python的可行性。 她离开后,我接手了。 现在,在这一胜利的时刻,我要感谢哈桑吉(Hasangi)率领整个Python行动。 👏
Chathura ,我们以前的另一个向导,已经使用Babel解决了IDE的整个NodeJS代码分析部分。 尽管在我的编译器理论讲座中有关于抽象语法树(AST)的课程,但经过他的代码后,我才真正“感受到”了AST的力量。 Chathura,这就是您的生命,它赋予了我们IDE的核心–并使我们的Python旅程大大加快了! 🖖
谢谢你
Chathura的工作很棒。 然而,这就像“水在水里”(哎呀,这是什么样的比喻?)。 换句话说,我们基本上是在ReactJS(yeah,JS)应用程序内解析(Node)JS代码。
因此,自然而然,我们的第一个问题(当时的百万美元问题)是:我们可以在JS应用程序中解析Python吗? 以及我们所有的魔术–为API调用呈现漂亮的弹出窗口,自动检测资源使用情况,自动生成IAM权限等吗?
Hasangi已经找到了filbert.js
,这是acorn
的衍生版本,可以解析Python。 不幸的是,不久之后,我和她了解到它无法理解AWS SDK API调用的标准(也是最受欢迎的)格式,即命名为params :
s3.put_object( Bucket= "foo" , Key= "bar" , Body=our_data )
如果我们改为使用“流利的”格式,请执行以下操作:
boto.connect_s3() \ .get_bucket( "foo" ) \ .new_key( "bar" ) \ .set_contents_from_string(our_data)
我们将不得不重写整个lotta AST解析逻辑; 也许是用于基于Python的用户区代码的全新AST解释器。 我们不想要那么多冒险-至少现在还没有。
(有用!!)
一个好的夜晚,我继续玩filbert.js
。 浏览解析路径时,我注意到:
... } else if (!noCalls && eat(_parenL)) { if (scope.isUserFunction(base.name)) { // Unpack parameters into JavaScript-friendly parameters, further processed at runtime var pl = parseParamsList(); ... node.arguments = args; } else node.arguments = parseExprList(_parenR, false ); ...
等等...他们故意跳过命名参数吗?
如果我注释掉该状况检查该怎么办?
... } else if (!noCalls && eat(_parenL)) { // if (scope.isUserFunction(base.name)) { // Unpack parameters into JavaScript-friendly parameters, further processed at runtime var pl = parseParamsList(); ... node.arguments = args; // } else node.arguments = parseExprList(_parenR, false); ...
然后……嗯,我简直不敢相信自己的眼睛。
注释了两行,它已经开始工作!
那是我的关键时刻。 我要把Python引入Sigma。 无论。
我不能放弃。 不追随我刚刚看到的。
大重构
当我们诞生Sigma时 ,它应该更像是PoC –证明我们无需本地开发人员设置,仪表板和文档往返以及大量配置即可进行无服务器开发。
结果,那时的可扩展性和可定制性还不太成熟。 事情几乎与AWS和NodeJS绑定在一起。 (并认为我们仍然称它们为“ JavaScript”文件…😁)
因此,从解析器开始,一大堆重构都在等待着我急切的手指。 从Language
抽象开始,我逐步完成了编辑器和弹出式渲染,代码段生成,构建工件,部署等工作。
( 在为Sigma提供Google Cloud支持时,我已经解决了类似的挑战-因此我对如何处理整个问题有一些了解。)
测试环境
自从Chathura(我们的前Adroit向导)一手实现它以来, 测试环境就成为Sigma功能集中最重要的一个。 如果Python产生了影响,我们还将需要一个Python测试环境。
这里的事情开始变得有些时髦。 由于它的历史有些尴尬 ,Python具有两个明显的“特色”:2.7和3.x。 因此,实际上,我们需要维护两个不同的环境-每个版本一个-并根据当前函数的运行时设置调用正确的环境。
(好吧,实际上,NodeJS也确实有同样的问题(6.x,8.x,10.x,...);但是显然我们没有考虑太多,也没有造成任何问题。也是主要问题!!)
pip install
我们还需要一种处理Python( pip
)依赖项的新方法。 幸运的是,Lambda容器上已经提供了pip
,因此安装不是主要问题。 真正的问题是必须将它们直接提取到测试环境中的项目根目录中。 (与npm
相反,这里的所有内容都进入一个漂亮且易于管理的node_modules
目录中,以便我们可以一次性提取和清理内容。)幸运的是,一点点(希望很稳定!)代码带领我们完成了工作。
没有
一切运行顺利,直到…
from subdirectory.util_file import util_func
, in <module> File "/tmp/pypy/ding.py" , line 1 , line from subdirectory.util_file import util_func ImportError: No module named subdirectory.util_file
仅在Python 2.7中发生过,因此这一点很容易弄清楚–我们需要在subdirectory
内部有一个__init__.py
来将其标记为可导入模块 。
我们决定不自己依靠用户来创建它,而是决定自己做。 每当创建Python文件时,我们现在都确保__init__.py
在其父目录中也存在; 如果没有文件,则创建一个空文件。
该死的原木–它们功能异常!
SigmaTrail是我们Sigma IDE的另一个瑰宝。 逐段编写Lambda时,在代码窗口旁边放置一个日志窗格确实有帮助。 此外,如果您看不到刚运行的日志,那么测试环境有什么用?
Chathura再次成为SigmaTrail的策划者。 (是的,毕竟,他编写了一半以上的IDE!)他的代码是谦虚地解析CloudWatch日志,并将它们与Lambda调用返回的LogResult
合并; 所以我想我可以将其插入Python运行时,坐下来欣赏一下视图。
我错了。
举起手来,那些使用Python
在Node中,您要从控制台中获得某种东西的唯一(显而易见的)方法(或从技术上来说是stdout
)是通过其中一个console.{level}()
调用。
但是Python提供了一些选择 –例如内置的print
和logging
模块。
如果要进行logging
,则必须:
-
import logging
- 创建一个
Logger
并设置其处理程序的级别-如果要生成调试日志等。 - 涉及到适当的
logger.{level}
或logging.{level}
方法
是的,在Lambda上,您还可以
context.log( "your log message\n" )
如果您的context
仍然存在-仍然需要在末尾添加\n
,以便将其记录到自己的行中。
但是,仅print("your log message")
更容易-哎呀,如果您使用的是2.x,则甚至不需要那些花括号!
对你有益。
但这对SigmaTrail造成了严重的问题。
uck
对于Node中的console.log
,Lambda自动为每个日志添加当前时间戳和请求ID( context.awsRequestId
)。 Chathura利用这些数据来分离出日志行,并在SigmaTrail中将它们显示为不错的线索。
但是现在,有了print
,就没有前缀了。 什么都没捡到。
解决这个问题可能是工作中最困难的部分。 我花了大约一个星期的时间来尝试理解代码(由于使用了基于工人的模式); 然后又一个星期尝试在不破坏NodeJS流程的情况下对其进行修复。
到现在为止,它应该相当稳定-并且能够处理随着时间的流逝可能抛出的任何其他语言。
“真正的”运行时:与
测试环境复活后,我以为所有麻烦都结束了。 “传统”构建(由CodeBuild驱动)和部署非常易于重构,因此我很高兴–甚至为初始版本提高了环保标志。
但是我犯了一个严重的错误。
直到我实际上通过API网关触发器调用已部署的Lambda时,我才意识到这一点。
{ "errorMessage" : "Unable to import module 'project-name/func'" }
什么...
Unable to import module 'project-name/func' : No module named 'subdirectory' : No module named
ma模块在哪里?
测试工作正常! 那么为什么不生产呢?
经过几次随机实验,并检查了其他框架生成的Python捆绑软件,我意识到罪魁祸首是我们的部署档案(zipfile)结构。
所有其他捆绑软件都具有顶层功能,但我们的捆绑软件将它们包含在目录(我们的“项目根目录”)中。 到目前为止,这对于NodeJS来说不是问题。 但是现在,无论我如何定义处理程序路径,AWS的Python运行时都找不到它!
改变项目结构将是一场灾难。 破坏几乎所有其他事物的风险太大。 一个更安全的想法是重写可用设置之一(例如特定于Python的环境变量),以某种方式将我们的根目录添加到PYTHONPATH
。
一个简单的技巧
是的,答案就在那里, PYTHONPATH
; 但我不想像这样覆盖掉来自AWS Gods的帮助。
因此,我开始深入研究Lambda运行时( 是的,再次 )以查找是否可以使用某些东西:
import os def handler(event, context): print(os.environ)
给出:
{ 'PATH' : '/var/lang/bin:/usr/local/bin:/usr/bin/:/bin:/opt/bin' , 'LD_LIBRARY_PATH' : '/var/lang/lib:/lib64:/usr/lib64:/var/runtime:/var/runtime/lib:/var/task:/var/task/lib:/opt/lib' , ... 'LAMBDA_TASK_ROOT' : '/var/task' , 'LAMBDA_RUNTIME_DIR' : '/var/runtime' , ... 'AWS_EXECUTION_ENV' : 'AWS_Lambda_python3.6' , '_HANDLER' : 'runner_python36.handler' , ... 'PYTHONPATH' : '/var/runtime' , 'SIGMA_AWS_ACC_ID' : 'nnnnnnnnnnnn' }
LAMBDA_RUNTIME_DIR
看起来是一个很有前途的选择; 但不幸的是,AWS拒绝了它。 每次部署均失败,并出现长期平均错误:
Lambda was unable to configure your environment variables because the environment variables you have provided contains reserved keys that are currently not supported for modification. this request: LAMBDA_RUNTIME_DIR Reserved keys used in request: LAMBDA_RUNTIME_DIR
但是,该调查显示出一些重要的信息:Lambda中的PYTHONPATH
并不像我想象的那样复杂或拥挤。
'PYTHONPATH' : '/var/runtime'
显然,Lambda的内部代理商对此并没有太在意。 只需拉出并阅读/var/runtime/awslambda/bootstrap.py
然后自己看看。 😎
ew
因此,我最终重写了PYTHONPATH
,以包含项目的根目录/var/task/project-name
(除了/var/runtime
)。 如果您希望在其中显示其他内容,请随时修改环境变量 -但不要把我们的片段留在后面!
从好的方面来说,这应该意味着我的功能也应该在其他平台上工作,因为PYTHONPATH
应该是跨平台的。
Google Cloud for Python –即将推出!
经过一些调整,我们也可以使Python在Google Cloud Functions上运行。 它已经在我们的暂存环境中; 只要GCP上线,它就会很幸运! 🎉
还有很长的路要走……但是Python已经存在并且正在不断发展!
您可以在当前版本的IDE中编写Python函数。 只需单击“ 项目”窗格右上方的加号(+)按钮,选择“ 新建Python函数文件” (或“ 新建Python文件” ),然后开始魔术吧!
当然, 让我们-世界-知道事情的发展!
翻译自: https://www.javacodegeeks.com/2019/09/sigma-ide-now-supports-python-serverless-lambda-functions.html