之前配置了 Seatable- 4.3.8 版本的环境,具体的配置操作参照:https://wiki.waringid.me/x/HQA1AQ以下的操作基于 Seatable-4.4.9。主要实现以下功能:
SeaTable 的 Python 脚本运行包含多个部分,SeaTable, Python scheduler, Python starter 和 Python runner,它们的功能与关系如下
COMPOSE_FILE='seatable-server.yml' COMPOSE_PATH_SEPARATOR=',' # system settings TIME_ZONE='Asia/Shanghai' # seatable server url SEATABLE_SERVER_HOSTNAME='seatable.waringid.me' SEATABLE_SERVER_PROTOCOL='https' # initial web admin SEATABLE_ADMIN_EMAIL='1377777@139.com' SEATABLE_ADMIN_PASSWORD='XXXXXX' # database SEATABLE_MYSQL_ROOT_PASSWORD='XXXXX' SEATABLE_DIR='/data/seatable' SEATABLE_PYTHON_PIPELINE_DB_NAME=scheduler SEATABLE_PYTHON_PIPELINE_MYSQL_ROOT_PASSWORD='XXXXXX' SEATABLE_PYTHON_PIPELINE_MYSQL_USER=python SEATABLE_PYTHON_PIPELINE_MYSQL_PASSWORD='XXXXXXX' PYTHON_TRANSFER_DIRECTORY_PATH=/data/seatable/python-pipeline/tmp PYTHON_SCHEDULER_AUTH_TOKEN=25d46ca953db0899c2ca9 PYTHON_SCHEDULER_URL=http://python-scheduler PYTHON_SCHEDULER_LOGS_DIR=/data/seatable/python-pipeline/logs/scheduler-logs PYTHON_STARTER_USE_ALTERNATIVE_FILE_SERVER_ROOT=True PYTHON_STARTER_ALTERNATIVE_FILE_SERVER_ROOT=http://seatable-server PYTHON_STARTER_LOGS_DIR=/data/seatable/python-pipeline/logs/starter-logs SEATABLE_SCHEDULER_IMAGE=seatable/seatable-python-scheduler:latest SEATABLE_STARTER_IMAGE=seatable/seatable-python-starter:3.1.1.p SEATABLE_RUNNER_IMAGE=seatable/seatable-python-runner:latest |
SEATABLE_FAAS_URL = 'http://python-scheduler' SEATABLE_FAAS_AUTH_TOKEN = '***' # 与 .env 文件 PYTHON_SCHEDULER_AUTH_TOKEN 的配置相同 |
--- services: seatable-server: image: ${SEATABLE_IMAGE:-seatable/seatable-enterprise:latest} restart: unless-stopped container_name: seatable-server ports: - "8006:80" volumes: - "${SEATABLE_DIR}/seatable-server:/shared" - "${SEATABLE_DIR}/deps/seatable.sh:/templates/seatable.sh:rx" - "${SEATABLE_DIR}/deps/licenseparse.py:/opt/seatable/seatable-server-latest/dtable-web/seahub/utils/licenseparse.py:rw" - "${SEATABLE_DIR}/deps/seafile-controller:/opt/seatable/seatable-server-latest/seafile/bin/seafile-controller:rw" - "${SEATABLE_DIR}/deps/seaf-server:/opt/seatable/seatable-server-latest/seafile/bin/seaf-server:rw" environment: - DB_HOST=mariadb - DB_ROOT_PASSWD=${SEATABLE_MYSQL_ROOT_PASSWORD:?Variable is not set or empty} - SEATABLE_SERVER_HOSTNAME=${SEATABLE_SERVER_HOSTNAME:?Variable is not set or empty} - SEATABLE_SERVER_PROTOCOL=${SEATABLE_SERVER_PROTOCOL:-https} - SEATABLE_ADMIN_EMAIL=${SEATABLE_ADMIN_EMAIL:?Variable is not set or empty} - SEATABLE_ADMIN_PASSWORD=${SEATABLE_ADMIN_PASSWORD:?Variable is not set or empty} - TIME_ZONE=${TIME_ZONE} depends_on: mariadb: condition: service_healthy memcached: condition: service_healthy redis: condition: service_healthy networks: - frontend-net - backend-seatable-net healthcheck: test: ["CMD-SHELL", "curl --fail http://localhost:8000 || exit 1"] interval: 20s retries: 3 start_period: 30s timeout: 10s mariadb: image: ${SEATABLE_DB_IMAGE:-mariadb:10.11.6} restart: unless-stopped container_name: mariadb environment: - MYSQL_ROOT_PASSWORD=${SEATABLE_MYSQL_ROOT_PASSWORD:?Variable is not set or empty} - MYSQL_LOG_CONSOLE=true - MARIADB_AUTO_UPGRADE=1 volumes: - "${SEATABLE_DIR}/mariadb:/var/lib/mysql" networks: - backend-seatable-net healthcheck: test: [ "CMD", "/usr/local/bin/healthcheck.sh", "--connect", "--mariadbupgrade", "--innodb_initialized", ] interval: 20s retries: 3 start_period: 30s timeout: 10s memcached: image: ${SEATABLE_MEMCACHED_IMAGE:-memcached:1.6.22} restart: unless-stopped container_name: memcached entrypoint: memcached -m 256 networks: - backend-seatable-net healthcheck: test: ["CMD-SHELL", "timeout 2 bash -c '</dev/tcp/localhost/11211'"] interval: 20s retries: 3 timeout: 5s redis: image: ${SEATABLE_REDIS_IMAGE:-redis:7.2.3} restart: unless-stopped container_name: redis networks: - backend-seatable-net healthcheck: test: ["CMD", "redis-cli", "ping"] interval: 20s retries: 3 timeout: 5s python-scheduler: image: ${SEATABLE_SCHEDULER_IMAGE:-seatable/seatable-python-scheduler:latest} restart: unless-stopped container_name: python-scheduler environment: - TIME_ZONE=${TIME_ZONE} - DATABASE_NAME=${SEATABLE_PYTHON_PIPELINE_MYSQL_DB_NAME:-scheduler} - DB_HOST=mariadb - DB_ROOT_PASSWD=${SEATABLE_PYTHON_PIPELINE_MYSQL_ROOT_PASSWORD:-} - DB_USER=${SEATABLE_PYTHON_PIPELINE_MYSQL_USER:-} - DB_PASSWD=${SEATABLE_PYTHON_PIPELINE_MYSQL_PASSWORD:-} - PYTHON_SCHEDULER_AUTH_TOKEN=${PYTHON_SCHEDULER_AUTH_TOKEN:?Variable is not set or empty} - SEATABLE_SERVER_URL=${SEATABLE_SERVER_PROTOCOL}://${SEATABLE_SERVER_HOSTNAME} - PYTHON_STARTER_URL=${PYTHON_STARTER_URL:-http://python-starter:8080} - PYTHON_SCHEDULER_LOG_LEVEL=${PYTHON_SCHEDULER_LOG_LEVEL:-WARNING} - DELETE_LOG_DAYS=${DELETE_LOG_DAYS:-30} - PYTHON_PROCESS_TIMEOUT=${PYTHON_PROCESS_TIMEOUT:-900} - PYTHON_SCHEDULER_SCRIPT_WORKERS=${PYTHON_SCHEDULER_SCRIPT_WORKERS:-5} volumes: - "${PYTHON_SCHEDULER_LOGS_DIR:-/tmp}:/opt/scheduler/logs" extra_hosts: - "host.docker.internal:host-gateway" networks: - backend-scheduler-net - frontend-net - backend-seatable-net depends_on: mariadb: condition: service_healthy healthcheck: test: [ "CMD-SHELL", "pgrep -f 'python3 scheduler.py' && pgrep -f 'python3 flask_server.py'", ] interval: 20s retries: 3 start_period: 20s timeout: 10s python-starter: image: ${SEATABLE_STARTER_IMAGE:-seatable/seatable-python-starter:latest} restart: unless-stopped container_name: python-starter volumes: - "/var/run/docker.sock:/var/run/docker.sock" - "${PYTHON_TRANSFER_DIRECTORY_PATH:-/tmp}:${PYTHON_TRANSFER_DIRECTORY_PATH:-/tmp}" - "${PYTHON_STARTER_LOGS_DIR:-/tmp}:/opt/seatable-python-starter/logs" environment: - TIME_ZONE=${TIME_ZONE} - PYTHON_SCHEDULER_URL=http://python-scheduler - PYTHON_TRANSFER_DIRECTORY=${PYTHON_TRANSFER_DIRECTORY_PATH:-/tmp} - PYTHON_RUNNER_IMAGE=${SEATABLE_RUNNER_IMAGE:-seatable/seatable-python-runner:latest} - PYTHON_STARTER_LOG_LEVEL=${PYTHON_STARTER_LOG_LEVEL:-WARNING} - PYTHON_PROCESS_TIMEOUT=${PYTHON_PROCESS_TIMEOUT:-900} - PYTHON_STARTER_THREAD_COUNT=${PYTHON_STARTER_THREAD_COUNT:-10} - PYTHON_STARTER_USE_ALTERNATIVE_FILE_SERVER_ROOT=${PYTHON_STARTER_USE_ALTERNATIVE_FILE_SERVER_ROOT:-} - PYTHON_STARTER_ALTERNATIVE_FILE_SERVER_ROOT=${PYTHON_STARTER_ALTERNATIVE_FILE_SERVER_ROOT:-} - PYTHON_RUNNER_OUTPUT_LIMIT=${PYTHON_RUNNER_OUTPUT_LIMIT:-1000000} - PYTHON_RUNNER_CONTAINER_MEMORY=${PYTHON_RUNNER_CONTAINER_MEMORY:-2g} - PYTHON_RUNNER_CONTAINER_CPUS=${PYTHON_RUNNER_CONTAINER_CPUS:-} - PYTHON_RUNNER_OTHER_OPTIONS=${PYTHON_RUNNER_OTHER_OPTIONS:-} networks: - backend-scheduler-net - frontend-net networks: frontend-net: name: frontend-net backend-seatable-net: name: backend-seatable-net backend-scheduler-net: name: backend-scheduler-net |
location /api-gateway/ { add_header Access-Control-Allow-Origin *; add_header Access-Control-Allow-Methods GET,POST,PUT,DELETE,OPTIONS; add_header Access-Control-Allow-Headers "deviceType,token, authorization, content-type"; if ($request_method = 'OPTIONS') { add_header Access-Control-Allow-Origin *; add_header Access-Control-Allow-Methods GET,POST,PUT,DELETE,OPTIONS; add_header Access-Control-Allow-Headers "deviceType,token, authorization, content-type"; return 204; } proxy_pass http://127.0.0.1:7780/; proxy_redirect off; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Host $server_name; proxy_set_header X-Forwarded-Proto $scheme; proxy_hide_header Access-Control-Allow-Origin; proxy_hide_header Access-Control-Allow-Methods; proxy_hide_header Access-Control-Allow-Headers; access_log /opt/nginx-logs/api-gateway.access.log seatableformat; error_log /opt/nginx-logs/api-gateway.error.log; } |
在 Photon5 为宿主机的容器环境下原有的镜像会出现 uwsgi crash 的情况,主要原因是因为配置文件设置存在问题导致
解决的办法是修改配置文件,然后将配置文件打包到镜像文件并在后续的应用中使用新的镜像文件。以下是经测试能正常应用 uwsgi.ini 配置文件内容
docker cp ./uwsgi.ini python-starter:/opt/seatable-python-starter/uwsgi.ini |
[uwsgi] http = :8080 wsgi-file = /opt/seatable-python-starter/runner.py uid = root gid = root chmod-socket = 660 callable = app max-fd = 1048576 process = 1 threads = 1 vacuum = true buffer-size = 65536 stats = 127.0.0.1:9191 procname-prefix = run-python logto = /opt/seatable-python-starter/logs/uwsgi.log log-level = info |
打开对应的表,我们需要在“商品档案1”表中按照“商品条码”(字符串类型,数字编码)自动生成对应的“条码”(图片类型,图片文件)
import os import time import barcode from barcode.writer import ImageWriter from seatable_api import Base, context api_token = context.api_token or "f83c266f818f4df4be30d8fdef8be7b5bbdd5bed" server_url = context.server_url or "https://seatable.waringid.me" TEXT_COL = "商品条码" # column which is expected to be transferred into barcode BARCODE_IMAGE_COL = "条码" TABLE_NAME = '商品档案' BARCODE_TYPE = 'code128' CUSTOM_OPTIONS = { "module_width": 0.2, # width of single stripe of barcode, mm "module_height": 15.0, # height of barcode, mm "quiet_zone": 6.5, # padding size of first and last stripe to the image, mm "font_size": 10, # font size of the text below the barcode,pt "text_distance": 5.0, # distance between the text and the barcode, mm } #print("test",TEXT_COL) CODE = barcode.get_barcode_class(BARCODE_TYPE) base = Base(api_token, server_url) base.auth() #rows1 = base.list_rows(TABLE_NAME,view_name='default', start=1005, limit=20) #rows2 = base.get_table_by_name(TABLE_NAME) def get_time_stamp(): return str(int(time.time()*100000)) #print("rows1",rows1) #print("rows2",rows2) for row in base.list_rows(TABLE_NAME,view_name='default', start=1001, limit=200): # continue if the image is already shown up here #print("image",row.get(BARCODE_IMAGE_COL)) if row.get(BARCODE_IMAGE_COL): continue if not row.get(TEXT_COL): continue try: row_id = row.get('_id') msg = str(row.get(TEXT_COL)) #print("row_id",row_id) #print("msg-numer",msg) # create a barcode object code_img = CODE(msg, writer=ImageWriter()) save_name = "%s_%s" % (row_id, get_time_stamp()) # temporarily saved as an image file_name = code_img.save("/tmp/%s" % save_name, options=CUSTOM_OPTIONS) # upload the barcode image to the base info_dict = base.upload_local_file(file_name, name=None, file_type='image', replace=True) img_url = info_dict.get('url') data = { "条码": [img_url] } #print("img_url",img_url) #print("row_id",row_id) print("msg-numer-",msg+"ok") base.update_row(TABLE_NAME, row_id, data) # remove the image file which is saved temporarily os.remove(file_name) except Exception as error: print("error occured during barcode generate", error) continue |
|