好吧,这其实并不是啥高深的东西。如果你升级之前老老实实看了 Changelog,就肯定不会跟我这么倒霉了。
这件事情还是今天我们的 Gitlab CI 莫名其妙挂掉了。日志如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
$ coverage run manage.py test --settings=takachiho.settings.testing --pattern="test_*.py" -v 2 DEBUG 2018-08-02 20:02:31,948 base 619 140240725620480 Configuring Raven for host: None INFO 2018-08-02 20:02:31,949 base 619 140240725620480 Raven is not configured (logging is disabled). Please see the documentation for more information. Creating test database for alias 'default' ('test_takachiho_temp')... Operations to perform: Synchronize unmigrated apps: admindocs, django_mptt_admin, messages, mptt, raven_contrib_django, staticfiles Apply all migrations: admin, alarm, auth, contenttypes, django_celery_beat, locator, metadata, monitor, noise_reductor, request_locator, sessions, utils Synchronizing apps without migrations: Creating tables... Running deferred SQL... Running migrations: Traceback (most recent call last): File "/usr/local/lib/python3.6/site-packages/django/db/backends/utils.py", line 83, in _execute return self.cursor.execute(sql) File "/usr/local/lib/python3.6/site-packages/django/db/backends/mysql/base.py", line 71, in execute return self.cursor.execute(query, args) File "/usr/local/lib/python3.6/site-packages/MySQLdb/cursors.py", line 250, in execute self.errorhandler(self, exc, value) File "/usr/local/lib/python3.6/site-packages/MySQLdb/connections.py", line 50, in defaulterrorhandler raise errorvalue File "/usr/local/lib/python3.6/site-packages/MySQLdb/cursors.py", line 247, in execute res = self._query(query) File "/usr/local/lib/python3.6/site-packages/MySQLdb/cursors.py", line 412, in _query rowcount = self._do_query(q) File "/usr/local/lib/python3.6/site-packages/MySQLdb/cursors.py", line 375, in _do_query db.query(q) File "/usr/local/lib/python3.6/site-packages/MySQLdb/connections.py", line 276, in query _mysql.connection.query(self, query) _mysql_exceptions.ProgrammingError: (1064, "You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '(6) NOT NULL)' at line 1") |
其中:
- 本地运行是 ok 的
- master 分支的CI是 ok 的
- 挂掉的那个分支添加了新的依赖 anytree
大量被浪费的时间……
一开始我怀疑是代码的变更导致生成了不合法的 SQL,于是仔细看了一遍 migrations,没发现什么异常(这是白费功夫,因为显然 migrations 还没开始执行就挂了)。
于是尝试打印出来执行的 SQL,因为 CI 是在 docker 跑的,于是我直接进入 docker ,修改 SQL syntax error 的那个文件,打印出来 q
,结果如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
Operations to perform: Synchronize unmigrated apps: admindocs, django_mptt_admin, messages, mptt, raven_contrib_django, staticfiles Apply all migrations: admin, alarm, auth, contenttypes, django_celery_beat, locator, metadata, monitor, noise_reductor, request_locator, sessions, utils Synchronizing apps without migrations: b'SHOW FULL TABLES' Creating tables... Running deferred SQL... Running migrations: b'SHOW FULL TABLES' b'CREATE TABLE `django_migrations` (`id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY, `app` varchar(255) NOT NULL, `name` varchar(255) NOT NULL, `applied` datetime(6) NOT NULL)' Traceback (most recent call last): File "/usr/local/lib/python3.6/site-packages/django/db/backends/utils.py", line 83, in _execute return self.cursor.execute(sql) File "/usr/local/lib/python3.6/site-packages/django/db/backends/mysql/base.py", line 71, in execute return self.cursor.execute(query, args) File "/usr/local/lib/python3.6/site-packages/MySQLdb/cursors.py", line 250, in execute self.errorhandler(self, exc, value) File "/usr/local/lib/python3.6/site-packages/MySQLdb/connections.py", line 50, in defaulterrorhandler raise errorvalue File "/usr/local/lib/python3.6/site-packages/MySQLdb/cursors.py", line 247, in execute res = self._query(query) File "/usr/local/lib/python3.6/site-packages/MySQLdb/cursors.py", line 413, in _query rowcount = self._do_query(q) File "/usr/local/lib/python3.6/site-packages/MySQLdb/cursors.py", line 376, in _do_query db.query(q) File "/usr/local/lib/python3.6/site-packages/MySQLdb/connections.py", line 276, in query _mysql.connection.query(self, query) _mysql_exceptions.ProgrammingError: (1064, "You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '(6) NOT NULL)' at line 1") |
我把这行代码拷贝到本机的 Mysql 执行,没问题啊(废话,我为啥要这么做啊…… Docker里面的 mysql 和我电脑上的明显版本不一样)。
于是在 Docker 的 mysql 执行,嗯,确实语法错误。而且我确认了是支持 datetime
不支持 datetime(6)
1 2 3 4 5 |
mysql> CREATE TABLE `django_migrations` (`id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY, `app` varchar(255) NOT NULL, `name` varchar(255) NOT NULL, `applied` datetime NOT NULL); Query OK, 0 rows affected (0.00 sec) mysql> CREATE TABLE `django_migrations` (`id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY, `app` varchar(255) NOT NULL, `name` varchar(255) NOT NULL, `applied` datetime(6) NOT NULL); ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '(6) NOT NULL)' at line 1 |
但是为啥之前好好地,突然就有问题了呢?唉,这里浪费的时间就不说了,总之我后来终于顿悟发觉是依赖更新了导致的。因为 requirements.txt
添加了一个新的 package ,里面所有的东西都重新安装过(新建的 Docker image),然后因为我们的 pip 没有锁版本,最近 Django 发布 2.1,CI 的 image 由默认的 2.0 版本升级到 2.1 了。
我用两个 Django 版本跑测试,打印出来 SQL 日志,发现两个版本生成的 SQL 语法确实不一样。
其中,Django2.0 创建 migrations 生成的 SQL 如下:
1 |
CREATE TABLE `django_migrations` (`id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY, `app` varchar(255) NOT NULL, `name` varchar(255) NOT NULL, `applied` datetime NOT NULL) |
然后当前 pip 默认版本的 Django 2.1 创建 migrations 生成的 SQL 如下:
1 |
CREATE TABLE `django_migrations` (`id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY, `app` varchar(255) NOT NULL, `name` varchar(255) NOT NULL, `applied` datetime(6) NOT NULL) |
唯一的不同就是 datetime
变成了 datetime(6)
。
而我们的 CI image 用的是 python-3.6-jessie ,apt-get 安装的 mysql 版本是 5.5,不支持 datetime(6)
这种语法。
但是好好的 migrations 咋说更新就更新了呢? I blame Django。
然后我就发现人家明确说不支持 Mysql 5.5 了:Dropped support for MySQL 5.5 好吧,算我活该。
反思:
- 测试环境和开发环境不一致是个坑
- 不锁定 pip 的版本是个坑,有点想用 Pipenv 了
- 思路不清晰,随着自己“无根据的猜测”去排查浪费了时间(
pip list
都是在 CI 打印出来的,认真看看就能发现) - 自己用的项目就应该好好的 watch,看 Changelog!