Skip to content

Conversation

@waketzheng
Copy link
Contributor

@waketzheng waketzheng commented Nov 15, 2025

Description

The mysql:latest Docker image now points to MySQL 9 (previously MySQL 8), with GTID mode enabled by default.

This breaks our CI tests for mysql that use the MyISAM storage engine.

https://github.com/tortoise/tortoise-orm/actions/runs/19282005009/job/55134921663

Motivation and Context

Turn off gtid_mode when runing make test_mysql_myisam and turn it back after this test

How Has This Been Tested?

make ci

Checklist:

  • My code follows the code style of this project.
  • My change requires a change to the documentation.
  • I have updated the documentation accordingly.
  • I have added the changelog accordingly.
  • I have read the CONTRIBUTING document.
  • I have added tests to cover my changes.
  • All new and existing tests passed.

@codspeed-hq
Copy link

codspeed-hq bot commented Nov 15, 2025

CodSpeed Performance Report

Merging #2016 will not alter performance

Comparing waketzheng:fix-mysql-myisam-test-error (11963b9) with develop (d3100ef)

Summary

✅ 16 untouched

@coveralls
Copy link

coveralls commented Nov 15, 2025

Pull Request Test Coverage Report for Build 19596316452

Details

  • 0 of 0 changed or added relevant lines in 0 files are covered.
  • No unchanged relevant lines lost coverage.
  • Overall coverage increased (+0.8%) to 90.708%

Totals Coverage Status
Change from base Build 17945632871: 0.8%
Covered Lines: 6626
Relevant Lines: 7190

💛 - Coveralls

Copy link
Contributor

@henadzit henadzit left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we should be changing the global parameters of the mysql server. This is quite an unexpected side effect of running tests.

To unblock the CI, we can just set the --gtid-mode parameter for the MySQL service in GitHub Actions. Here you can find an example of how to set an option for the service container https://docs.github.com/en/actions/tutorials/use-containerized-services/create-redis-service-containers

@henadzit
Copy link
Contributor

This should do it too, thanks!

@henadzit henadzit merged commit 5cac58d into tortoise:develop Nov 23, 2025
9 checks passed
@waketzheng
Copy link
Contributor Author

For MySQL9.0+, GTID mode can be set off by the following script:

from __future__ import annotations

import asyncio
import contextlib
import os
import sys
from collections.abc import AsyncGenerator
from contextlib import asynccontextmanager

from tortoise import BaseDBAsyncClient, connections
from tortoise.backends.base.config_generator import expand_db_url
from tortoise.exceptions import OperationalError


@asynccontextmanager
async def tortoise_context() -> AsyncGenerator[BaseDBAsyncClient]:
    password = os.getenv("TORTOISE_MYSQL_PASS", "123456")
    db_url = f"mysql://root:{password}@127.0.0.1:3306/mysql"
    connections_config = {"default": expand_db_url(db_url)}
    await connections._init(connections_config, create_db=False)
    try:
        yield connections.get("default")
    finally:
        await connections.close_all()


class MysqlGtid:
    def __init__(self, conn: BaseDBAsyncClient) -> None:
        self.conn = conn

    async def get_var_value(self, statement: str) -> str:
        print(f"--> {statement}")
        result = await self.conn.execute_query_dict(statement)
        return str(result[0]["Value"])

    async def get_gtid_consistency(self) -> str:
        statement = "SHOW VARIABLES LIKE 'enforce_gtid_consistency';"
        return await self.get_var_value(statement)

    async def is_enforce_gtid(self) -> bool:
        return (await self.get_gtid_consistency()).upper() == "ON"

    async def get_gtid_mode_status(self) -> str:
        statement = "SHOW VARIABLES LIKE 'gtid_mode';"
        return await self.get_var_value(statement)

    async def execute_script(self, statement: str) -> None:
        print(f"--> {statement}")
        await self.conn.execute_script(statement)

    async def set_enforce_gtid_off(self, mode_on: bool, gtid_mode: str) -> None:
        statement = "SET GLOBAL enforce_gtid_consistency = OFF;"
        if mode_on:
            if gtid_mode == "ON":
                await self.execute_script("SET GLOBAL gtid_mode = ON_PERMISSIVE;")
            await self.execute_script("SET GLOBAL gtid_mode = OFF_PERMISSIVE;")
            await self.execute_script("SET GLOBAL gtid_mode = OFF;")
        await self.execute_script(statement)

    async def set_enforce_gtid_on(self, mode_on: bool, origin_gtid_mode: str) -> None:
        statement = "SET GLOBAL enforce_gtid_consistency = ON;"
        await self.execute_script(statement)
        if mode_on:
            current_status = (await self.get_gtid_mode_status()).upper()
            if current_status == origin_gtid_mode.upper():
                return
            with contextlib.suppress(OperationalError):
                if current_status == "OFF":
                    await self.execute_script("SET GLOBAL gtid_mode = OFF_PERMISSIVE;")
                await self.execute_script("SET GLOBAL gtid_mode = ON_PERMISSIVE;")
                if origin_gtid_mode.upper() == "ON":
                    await self.execute_script("SET GLOBAL gtid_mode = ON;")


async def main() -> None:
    async with tortoise_context() as conn:
        db = MysqlGtid(conn)
        if "--list" in sys.argv:
            print(await db.get_gtid_consistency())
            print(await db.get_gtid_mode_status())
        elif "--on" in sys.argv:
            if (await db.get_gtid_mode_status()).upper() == "ON":
                print("gtid_mode is ON, nothing to do.")
                return
            await db.set_enforce_gtid_on(True, "ON")
        else:
            if not await db.is_enforce_gtid():
                print("enforce_gtid_consistency is OFF, nothing to do.")
                return
            origin_gtid_mode = await db.get_gtid_mode_status()
            gtid_mode = origin_gtid_mode.upper()
            mode_on = gtid_mode.startswith("ON")
            await db.set_enforce_gtid_off(mode_on, gtid_mode)


if __name__ == "__main__":
    asyncio.run(main())

@waketzheng waketzheng deleted the fix-mysql-myisam-test-error branch November 23, 2025 14:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants