F 修复发布日志可能记录不完整的问题

pull/59/head
vapao 2020-03-31 13:07:01 +08:00
parent 5e15e348a1
commit bebd5277ee
4 changed files with 60 additions and 42 deletions

View File

@ -21,7 +21,7 @@ def deploy_dispatch(request, req, token):
try:
api_token = uuid.uuid4().hex
rds.setex(api_token, 60 * 60, f'{req.deploy.app_id},{req.deploy.env_id}')
helper = Helper(rds, token)
helper = Helper(rds, token, req.id)
helper.send_step('local', 1, f'完成\r\n{human_time()} 发布准备... ')
env = AttrDict(
SPUG_APP_NAME=req.deploy.app.name,
@ -177,9 +177,11 @@ def _deploy_ext2_host(helper, h_id, actions, env):
class Helper:
def __init__(self, rds, token):
def __init__(self, rds, token, r_id):
self.rds = rds
self.token = token
self.log_key = f'{settings.REQUEST_KEY}:{r_id}'
self.rds.delete(self.log_key)
@staticmethod
def send_deploy_notify(req):
@ -235,16 +237,20 @@ class Helper:
files.append(line)
return files
def _send(self, message):
self.rds.lpush(self.token, json.dumps(message))
self.rds.lpush(self.log_key, json.dumps(message))
def send_info(self, key, message):
self.rds.lpush(self.token, json.dumps({'key': key, 'status': 'info', 'data': message}))
self._send({'key': key, 'status': 'info', 'data': message})
def send_error(self, key, message):
message = '\r\n' + message
self.rds.lpush(self.token, json.dumps({'key': key, 'status': 'error', 'data': message}))
self._send({'key': key, 'status': 'error', 'data': message})
raise Exception(message)
def send_step(self, key, step, data):
self.rds.lpush(self.token, json.dumps({'key': key, 'step': step, 'data': data}))
self._send({'key': key, 'step': step, 'data': data})
def local(self, command, env=None):
command = 'set -e\n' + command

View File

@ -3,24 +3,17 @@
# Released under the MIT License.
from channels.generic.websocket import WebsocketConsumer
from django_redis import get_redis_connection
from django.conf import settings
from apps.setting.utils import AppSetting
from apps.host.models import Host
from threading import Thread
from urllib.parse import parse_qs
import json
class ExecConsumer(WebsocketConsumer):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
query = parse_qs(self.scope['query_string'].decode())
e_id = query.get('id', [None])[0]
self.token = self.scope['url_route']['kwargs']['token']
self.log_key = f'{settings.REQUEST_KEY}:{e_id}' if e_id else None
self.rds = get_redis_connection()
if self.log_key:
self.rds.delete(self.log_key)
def connect(self):
self.accept()
@ -29,11 +22,8 @@ class ExecConsumer(WebsocketConsumer):
self.rds.close()
def get_response(self):
if self.log_key:
return self.rds.brpoplpush(self.token, self.log_key, timeout=5)
else:
response = self.rds.brpop(self.token, timeout=5)
return response[1] if response else None
response = self.rds.brpop(self.token, timeout=5)
return response[1] if response else None
def receive(self, **kwargs):
response = self.get_response()

View File

@ -17,6 +17,8 @@ import lds from 'lodash';
class Ext1Index extends React.Component {
constructor(props) {
super(props);
this.id = props.match.params.id;
this.log = props.match.params.log;
this.state = {
fetching: true,
loading: false,
@ -25,11 +27,21 @@ class Ext1Index extends React.Component {
}
componentDidMount() {
this.id = this.props.match.params.id;
this.log = this.props.match.params.log;
this.fetch()
}
componentWillUnmount() {
if (this.socket) this.socket.close();
store.request = {targets: [], host_actions: [], server_actions: []};
store.outputs = {};
}
fetch = () => {
this.setState({fetching: true});
http.get(`/api/deploy/request/${this.id}/`, {params: {log: this.log}})
.then(res => {
store.request = res;
store.outputs = {};
while (res.outputs.length) {
const msg = JSON.parse(res.outputs.pop());
if (!store.outputs.hasOwnProperty(msg.key)) {
@ -40,13 +52,7 @@ class Ext1Index extends React.Component {
}
})
.finally(() => this.setState({fetching: false}))
}
componentWillUnmount() {
if (this.socket) this.socket.close();
store.request = {targets: [], host_actions: [], server_actions: []};
store.outputs = {};
}
};
_parse_message = (message) => {
const {key, data, step, status} = message;
@ -62,7 +68,7 @@ class Ext1Index extends React.Component {
store.request.status = '2';
store.outputs = outputs;
const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
this.socket = new WebSocket(`${protocol}//${window.location.host}/api/ws/exec/${token}/?id=${this.id}`);
this.socket = new WebSocket(`${protocol}//${window.location.host}/api/ws/exec/${token}/`);
this.socket.onopen = () => {
this.socket.send('ok');
};
@ -115,9 +121,13 @@ class Ext1Index extends React.Component {
subTitle={`${app_name} - ${env_name}`}
style={{padding: 0}}
tags={this.getStatusAlias()}
extra={<Button loading={this.state.loading} type="primary"
disabled={this.log || !['1', '-3'].includes(status)}
onClick={this.handleDeploy}>发布</Button>}
extra={this.log ? (
<Button icon="sync" type="primary" onClick={this.fetch}>刷新</Button>
) : (
<Button icon="play-circle" loading={this.state.loading} type="primary"
disabled={!['1', '-3'].includes(status)}
onClick={this.handleDeploy}>发布</Button>
)}
onBack={() => history.goBack()}/>
<Collapse defaultActiveKey={1} className={styles.collapse}>
<Collapse.Panel showArrow={false} key={1} header={

View File

@ -17,6 +17,8 @@ import lds from 'lodash';
class Ext1Index extends React.Component {
constructor(props) {
super(props);
this.id = props.match.params.id;
this.log = props.match.params.log;
this.state = {
fetching: true,
loading: false,
@ -25,11 +27,22 @@ class Ext1Index extends React.Component {
}
componentDidMount() {
this.id = this.props.match.params.id;
this.log = this.props.match.params.log;
this.fetch()
}
componentWillUnmount() {
if (this.socket) this.socket.close();
store.request = {targets: [], server_actions: [], host_actions: []};
store.outputs = {};
}
fetch = () => {
this.setState({fetching: true});
http.get(`/api/deploy/request/${this.id}/`, {params: {log: this.log}})
.then(res => {
store.request = res;
store.outputs = {};
while (res.outputs.length) {
const msg = JSON.parse(res.outputs.pop());
if (!store.outputs.hasOwnProperty(msg.key)) {
@ -40,13 +53,7 @@ class Ext1Index extends React.Component {
}
})
.finally(() => this.setState({fetching: false}))
}
componentWillUnmount() {
if (this.socket) this.socket.close();
store.request = {targets: [], server_actions: [], host_actions: []};
store.outputs = {};
}
};
_parse_message = (message) => {
const {key, data, step, status} = message;
@ -62,7 +69,7 @@ class Ext1Index extends React.Component {
store.request.status = '2';
store.outputs = outputs;
const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
this.socket = new WebSocket(`${protocol}//${window.location.host}/api/ws/exec/${token}/?id=${this.id}`);
this.socket = new WebSocket(`${protocol}//${window.location.host}/api/ws/exec/${token}/`);
this.socket.onopen = () => {
this.socket.send('ok');
};
@ -115,8 +122,13 @@ class Ext1Index extends React.Component {
subTitle={`${app_name} - ${env_name}`}
style={{padding: 0}}
tags={this.getStatusAlias()}
extra={<Button loading={this.state.loading} type="primary" disabled={this.log || !['1', '-3'].includes(status)}
onClick={this.handleDeploy}>发布</Button>}
extra={this.log ? (
<Button icon="sync" type="primary" onClick={this.fetch}>刷新</Button>
) : (
<Button icon="play-circle" loading={this.state.loading} type="primary"
disabled={!['1', '-3'].includes(status)}
onClick={this.handleDeploy}>发布</Button>
)}
onBack={() => history.goBack()}/>
<Collapse defaultActiveKey={1} className={styles.collapse}>
<Collapse.Panel showArrow={false} key={1} header={